| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588 |
- /* eslint-disable @typescript-eslint/no-non-null-assertion */
- import { omit } from '@vendure/common/lib/omit';
- import { pick } from '@vendure/common/lib/pick';
- import { mergeConfig } from '@vendure/core';
- import { createTestEnvironment } from '@vendure/testing';
- import fs from 'fs-extra';
- import path from 'path';
- import { afterAll, beforeAll, describe, expect, it } from 'vitest';
- import { initialData } from '../../../e2e-common/e2e-initial-data';
- import { TEST_SETUP_TIMEOUT_MS, testConfig } from '../../../e2e-common/test-config';
- import * as Codegen from './graphql/generated-e2e-admin-types';
- import {
- AssetWithTagsAndFocalPointFragment,
- CreateAssetsMutation,
- DeletionResult,
- GetProductWithVariantsQuery,
- LogicalOperator,
- SortOrder,
- } from './graphql/generated-e2e-admin-types';
- import {
- CREATE_ASSETS,
- DELETE_ASSET,
- GET_ASSET,
- GET_ASSET_FRAGMENT_FIRST,
- GET_ASSET_LIST,
- GET_PRODUCT_WITH_VARIANTS,
- UPDATE_ASSET,
- } from './graphql/shared-definitions';
- describe('Asset resolver', () => {
- const { server, adminClient } = createTestEnvironment(
- mergeConfig(testConfig(), {
- assetOptions: {
- permittedFileTypes: ['image/*', '.pdf', '.zip'],
- },
- }),
- );
- let firstAssetId: string;
- let createdAssetId: string;
- beforeAll(async () => {
- await server.init({
- initialData,
- productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-full.csv'),
- customerCount: 1,
- });
- await adminClient.asSuperAdmin();
- }, TEST_SETUP_TIMEOUT_MS);
- afterAll(async () => {
- await server.destroy();
- });
- it('assets', async () => {
- const { assets } = await adminClient.query<
- Codegen.GetAssetListQuery,
- Codegen.GetAssetListQueryVariables
- >(GET_ASSET_LIST, {
- options: {
- sort: {
- name: SortOrder.ASC,
- },
- },
- });
- expect(assets.totalItems).toBe(4);
- expect(assets.items.map(a => omit(a, ['id']))).toEqual([
- {
- fileSize: 1680,
- mimeType: 'image/jpeg',
- name: 'alexandru-acea-686569-unsplash.jpg',
- preview: 'test-url/test-assets/alexandru-acea-686569-unsplash__preview.jpg',
- source: 'test-url/test-assets/alexandru-acea-686569-unsplash.jpg',
- type: 'IMAGE',
- },
- {
- fileSize: 1680,
- mimeType: 'image/jpeg',
- name: 'derick-david-409858-unsplash.jpg',
- preview: 'test-url/test-assets/derick-david-409858-unsplash__preview.jpg',
- source: 'test-url/test-assets/derick-david-409858-unsplash.jpg',
- type: 'IMAGE',
- },
- {
- fileSize: 1680,
- mimeType: 'image/jpeg',
- name: 'florian-olivo-1166419-unsplash.jpg',
- preview: 'test-url/test-assets/florian-olivo-1166419-unsplash__preview.jpg',
- source: 'test-url/test-assets/florian-olivo-1166419-unsplash.jpg',
- type: 'IMAGE',
- },
- {
- fileSize: 1680,
- mimeType: 'image/jpeg',
- name: 'vincent-botta-736919-unsplash.jpg',
- preview: 'test-url/test-assets/vincent-botta-736919-unsplash__preview.jpg',
- source: 'test-url/test-assets/vincent-botta-736919-unsplash.jpg',
- type: 'IMAGE',
- },
- ]);
- firstAssetId = assets.items[0].id;
- });
- it('asset', async () => {
- const { asset } = await adminClient.query<Codegen.GetAssetQuery, Codegen.GetAssetQueryVariables>(
- GET_ASSET,
- {
- id: firstAssetId,
- },
- );
- expect(asset).toEqual({
- fileSize: 1680,
- height: 48,
- id: firstAssetId,
- mimeType: 'image/jpeg',
- name: 'alexandru-acea-686569-unsplash.jpg',
- preview: 'test-url/test-assets/alexandru-acea-686569-unsplash__preview.jpg',
- source: 'test-url/test-assets/alexandru-acea-686569-unsplash.jpg',
- type: 'IMAGE',
- width: 48,
- });
- });
- /**
- * https://github.com/vendurehq/vendure/issues/459
- */
- it('transforms URL when fragment defined before query (GH issue #459)', async () => {
- const { asset } = await adminClient.query<
- Codegen.GetAssetFragmentFirstQuery,
- Codegen.GetAssetFragmentFirstQueryVariables
- >(GET_ASSET_FRAGMENT_FIRST, {
- id: firstAssetId,
- });
- expect(asset?.preview).toBe('test-url/test-assets/alexandru-acea-686569-unsplash__preview.jpg');
- });
- describe('createAssets', () => {
- function isAsset(
- input: CreateAssetsMutation['createAssets'][number],
- ): input is AssetWithTagsAndFocalPointFragment {
- return input.hasOwnProperty('name');
- }
- it('permitted types by mime type', async () => {
- const filesToUpload = [
- path.join(__dirname, 'fixtures/assets/pps1.jpg'),
- path.join(__dirname, 'fixtures/assets/pps2.jpg'),
- ];
- const { createAssets }: Codegen.CreateAssetsMutation = await adminClient.fileUploadMutation({
- mutation: CREATE_ASSETS,
- filePaths: filesToUpload,
- mapVariables: filePaths => ({
- input: filePaths.map(p => ({ file: null })),
- }),
- });
- expect(createAssets.length).toBe(2);
- const results = createAssets.filter(isAsset);
- expect(results.map(a => omit(a, ['id'])).sort((a, b) => (a.name < b.name ? -1 : 1))).toEqual([
- {
- fileSize: 1680,
- focalPoint: null,
- mimeType: 'image/jpeg',
- name: 'pps1.jpg',
- preview: 'test-url/test-assets/pps1__preview.jpg',
- source: 'test-url/test-assets/pps1.jpg',
- tags: [],
- type: 'IMAGE',
- },
- {
- fileSize: 1680,
- focalPoint: null,
- mimeType: 'image/jpeg',
- name: 'pps2.jpg',
- preview: 'test-url/test-assets/pps2__preview.jpg',
- source: 'test-url/test-assets/pps2.jpg',
- tags: [],
- type: 'IMAGE',
- },
- ]);
- createdAssetId = results[0].id;
- });
- it('permitted type by file extension', async () => {
- const filesToUpload = [path.join(__dirname, 'fixtures/assets/dummy.pdf')];
- const { createAssets }: Codegen.CreateAssetsMutation = await adminClient.fileUploadMutation({
- mutation: CREATE_ASSETS,
- filePaths: filesToUpload,
- mapVariables: filePaths => ({
- input: filePaths.map(p => ({ file: null })),
- }),
- });
- expect(createAssets.length).toBe(1);
- const results = createAssets.filter(isAsset);
- expect(results.map(a => omit(a, ['id']))).toEqual([
- {
- fileSize: 1680,
- focalPoint: null,
- mimeType: 'application/pdf',
- name: 'dummy.pdf',
- preview: 'test-url/test-assets/dummy__preview.pdf.png',
- source: 'test-url/test-assets/dummy.pdf',
- tags: [],
- type: 'BINARY',
- },
- ]);
- });
- // https://github.com/vendurehq/vendure/issues/727
- it('file extension with shared type', async () => {
- const filesToUpload = [path.join(__dirname, 'fixtures/assets/dummy.zip')];
- const { createAssets }: Codegen.CreateAssetsMutation = await adminClient.fileUploadMutation({
- mutation: CREATE_ASSETS,
- filePaths: filesToUpload,
- mapVariables: filePaths => ({
- input: filePaths.map(p => ({ file: null })),
- }),
- });
- expect(createAssets.length).toBe(1);
- expect(isAsset(createAssets[0])).toBe(true);
- const results = createAssets.filter(isAsset);
- expect(results.map(a => omit(a, ['id']))).toEqual([
- {
- fileSize: 1680,
- focalPoint: null,
- mimeType: 'application/zip',
- name: 'dummy.zip',
- preview: 'test-url/test-assets/dummy__preview.zip.png',
- source: 'test-url/test-assets/dummy.zip',
- tags: [],
- type: 'BINARY',
- },
- ]);
- });
- it('not permitted type', async () => {
- const filesToUpload = [path.join(__dirname, 'fixtures/assets/dummy.txt')];
- const { createAssets }: Codegen.CreateAssetsMutation = await adminClient.fileUploadMutation({
- mutation: CREATE_ASSETS,
- filePaths: filesToUpload,
- mapVariables: filePaths => ({
- input: filePaths.map(p => ({ file: null })),
- }),
- });
- expect(createAssets.length).toBe(1);
- expect(createAssets[0]).toEqual({
- message: 'The MIME type "text/plain" is not permitted.',
- mimeType: 'text/plain',
- fileName: 'dummy.txt',
- });
- });
- it('create with new tags', async () => {
- const filesToUpload = [path.join(__dirname, 'fixtures/assets/pps1.jpg')];
- const { createAssets }: Codegen.CreateAssetsMutation = await adminClient.fileUploadMutation({
- mutation: CREATE_ASSETS,
- filePaths: filesToUpload,
- mapVariables: filePaths => ({
- input: filePaths.map(p => ({ file: null, tags: ['foo', 'bar'] })),
- }),
- });
- const results = createAssets.filter(isAsset);
- expect(results.map(a => pick(a, ['id', 'name', 'tags']))).toEqual([
- {
- id: 'T_9',
- name: 'pps1.jpg',
- tags: [
- { id: 'T_1', value: 'foo' },
- { id: 'T_2', value: 'bar' },
- ],
- },
- ]);
- });
- it('create with existing tags', async () => {
- const filesToUpload = [path.join(__dirname, 'fixtures/assets/pps1.jpg')];
- const { createAssets }: Codegen.CreateAssetsMutation = await adminClient.fileUploadMutation({
- mutation: CREATE_ASSETS,
- filePaths: filesToUpload,
- mapVariables: filePaths => ({
- input: filePaths.map(p => ({ file: null, tags: ['foo', 'bar'] })),
- }),
- });
- const results = createAssets.filter(isAsset);
- expect(results.map(a => pick(a, ['id', 'name', 'tags']))).toEqual([
- {
- id: 'T_10',
- name: 'pps1.jpg',
- tags: [
- { id: 'T_1', value: 'foo' },
- { id: 'T_2', value: 'bar' },
- ],
- },
- ]);
- });
- it('create with new and existing tags', async () => {
- const filesToUpload = [path.join(__dirname, 'fixtures/assets/pps1.jpg')];
- const { createAssets }: Codegen.CreateAssetsMutation = await adminClient.fileUploadMutation({
- mutation: CREATE_ASSETS,
- filePaths: filesToUpload,
- mapVariables: filePaths => ({
- input: filePaths.map(p => ({ file: null, tags: ['quux', 'bar'] })),
- }),
- });
- const results = createAssets.filter(isAsset);
- expect(results.map(a => pick(a, ['id', 'name', 'tags']))).toEqual([
- {
- id: 'T_11',
- name: 'pps1.jpg',
- tags: [
- { id: 'T_3', value: 'quux' },
- { id: 'T_2', value: 'bar' },
- ],
- },
- ]);
- });
- // https://github.com/vendurehq/vendure/issues/990
- it('errors if the filesize is too large', async () => {
- /**
- * Based on https://stackoverflow.com/a/49433633/772859
- */
- function createEmptyFileOfSize(fileName: string, sizeInBytes: number) {
- return new Promise((resolve, reject) => {
- const fh = fs.openSync(fileName, 'w');
- fs.writeSync(fh, 'ok', Math.max(0, sizeInBytes - 2));
- fs.closeSync(fh);
- resolve(true);
- });
- }
- const twentyOneMib = 22020096;
- const filename = path.join(__dirname, 'fixtures/assets/temp_large_file.pdf');
- await createEmptyFileOfSize(filename, twentyOneMib);
- try {
- const { createAssets }: Codegen.CreateAssetsMutation = await adminClient.fileUploadMutation({
- mutation: CREATE_ASSETS,
- filePaths: [filename],
- mapVariables: filePaths => ({
- input: filePaths.map(p => ({ file: null })),
- }),
- });
- fail('Should have thrown');
- } catch (e: any) {
- expect(e.message).toContain('File truncated as it exceeds the 20971520 byte size limit');
- } finally {
- fs.rmSync(filename);
- }
- });
- });
- describe('filter by tags', () => {
- it('and', async () => {
- const { assets } = await adminClient.query<
- Codegen.GetAssetListQuery,
- Codegen.GetAssetListQueryVariables
- >(GET_ASSET_LIST, {
- options: {
- tags: ['foo', 'bar'],
- tagsOperator: LogicalOperator.AND,
- },
- });
- expect(assets.items.map(i => i.id).sort()).toEqual(['T_10', 'T_9']);
- });
- it('or', async () => {
- const { assets } = await adminClient.query<
- Codegen.GetAssetListQuery,
- Codegen.GetAssetListQueryVariables
- >(GET_ASSET_LIST, {
- options: {
- tags: ['foo', 'bar'],
- tagsOperator: LogicalOperator.OR,
- },
- });
- expect(assets.items.map(i => i.id).sort()).toEqual(['T_10', 'T_11', 'T_9']);
- });
- it('empty array', async () => {
- const { assets } = await adminClient.query<
- Codegen.GetAssetListQuery,
- Codegen.GetAssetListQueryVariables
- >(GET_ASSET_LIST, {
- options: {
- tags: [],
- },
- });
- expect(assets.totalItems).toBe(11);
- });
- });
- describe('updateAsset', () => {
- it('update name', async () => {
- const { updateAsset } = await adminClient.query<
- Codegen.UpdateAssetMutation,
- Codegen.UpdateAssetMutationVariables
- >(UPDATE_ASSET, {
- input: {
- id: firstAssetId,
- name: 'new name',
- },
- });
- expect(updateAsset.name).toEqual('new name');
- });
- it('update focalPoint', async () => {
- const { updateAsset } = await adminClient.query<
- Codegen.UpdateAssetMutation,
- Codegen.UpdateAssetMutationVariables
- >(UPDATE_ASSET, {
- input: {
- id: firstAssetId,
- focalPoint: {
- x: 0.3,
- y: 0.9,
- },
- },
- });
- expect(updateAsset.focalPoint).toEqual({
- x: 0.3,
- y: 0.9,
- });
- });
- it('unset focalPoint', async () => {
- const { updateAsset } = await adminClient.query<
- Codegen.UpdateAssetMutation,
- Codegen.UpdateAssetMutationVariables
- >(UPDATE_ASSET, {
- input: {
- id: firstAssetId,
- focalPoint: null,
- },
- });
- expect(updateAsset.focalPoint).toEqual(null);
- });
- it('update tags', async () => {
- const { updateAsset } = await adminClient.query<
- Codegen.UpdateAssetMutation,
- Codegen.UpdateAssetMutationVariables
- >(UPDATE_ASSET, {
- input: {
- id: firstAssetId,
- tags: ['foo', 'quux'],
- },
- });
- expect(updateAsset.tags).toEqual([
- { id: 'T_1', value: 'foo' },
- { id: 'T_3', value: 'quux' },
- ]);
- });
- it('remove tags', async () => {
- const { updateAsset } = await adminClient.query<
- Codegen.UpdateAssetMutation,
- Codegen.UpdateAssetMutationVariables
- >(UPDATE_ASSET, {
- input: {
- id: firstAssetId,
- tags: [],
- },
- });
- expect(updateAsset.tags).toEqual([]);
- });
- });
- describe('deleteAsset', () => {
- let firstProduct: NonNullable<GetProductWithVariantsQuery['product']>;
- beforeAll(async () => {
- const { product } = await adminClient.query<
- Codegen.GetProductWithVariantsQuery,
- Codegen.GetProductWithVariantsQueryVariables
- >(GET_PRODUCT_WITH_VARIANTS, {
- id: 'T_1',
- });
- firstProduct = product!;
- });
- it('non-featured asset', async () => {
- const { deleteAsset } = await adminClient.query<
- Codegen.DeleteAssetMutation,
- Codegen.DeleteAssetMutationVariables
- >(DELETE_ASSET, {
- input: {
- assetId: createdAssetId,
- },
- });
- expect(deleteAsset.result).toBe(DeletionResult.DELETED);
- const { asset } = await adminClient.query<Codegen.GetAssetQuery, Codegen.GetAssetQueryVariables>(
- GET_ASSET,
- {
- id: createdAssetId,
- },
- );
- expect(asset).toBeNull();
- });
- it('featured asset not deleted', async () => {
- const { deleteAsset } = await adminClient.query<
- Codegen.DeleteAssetMutation,
- Codegen.DeleteAssetMutationVariables
- >(DELETE_ASSET, {
- input: {
- assetId: firstProduct.featuredAsset!.id,
- },
- });
- expect(deleteAsset.result).toBe(DeletionResult.NOT_DELETED);
- expect(deleteAsset.message).toContain('The selected Asset is featured by 1 Product');
- const { asset } = await adminClient.query<Codegen.GetAssetQuery, Codegen.GetAssetQueryVariables>(
- GET_ASSET,
- {
- id: firstAssetId,
- },
- );
- expect(asset).not.toBeNull();
- });
- it('featured asset force deleted', async () => {
- const { product: p1 } = await adminClient.query<
- Codegen.GetProductWithVariantsQuery,
- Codegen.GetProductWithVariantsQueryVariables
- >(GET_PRODUCT_WITH_VARIANTS, {
- id: firstProduct.id,
- });
- expect(p1!.assets.length).toEqual(1);
- const { deleteAsset } = await adminClient.query<
- Codegen.DeleteAssetMutation,
- Codegen.DeleteAssetMutationVariables
- >(DELETE_ASSET, {
- input: {
- assetId: firstProduct.featuredAsset!.id,
- force: true,
- },
- });
- expect(deleteAsset.result).toBe(DeletionResult.DELETED);
- const { asset } = await adminClient.query<Codegen.GetAssetQuery, Codegen.GetAssetQueryVariables>(
- GET_ASSET,
- {
- id: firstAssetId,
- },
- );
- expect(asset).not.toBeNull();
- const { product } = await adminClient.query<
- Codegen.GetProductWithVariantsQuery,
- Codegen.GetProductWithVariantsQueryVariables
- >(GET_PRODUCT_WITH_VARIANTS, {
- id: firstProduct.id,
- });
- expect(product!.featuredAsset).toBeNull();
- expect(product!.assets.length).toEqual(0);
- });
- });
- });
|