import fs from 'fs'; import path from 'path'; import FormData from 'form-data'; import { promisify } from 'util'; import { initPayloadTest } from '../helpers/configHelpers'; import { RESTClient } from '../helpers/rest'; import configPromise, { mediaSlug, relationSlug } from './config'; import payload from '../../src'; import getFileByPath from '../../src/uploads/getFileByPath'; const stat = promisify(fs.stat); require('isomorphic-fetch'); let client; describe('Collections - Uploads', () => { beforeAll(async () => { const { serverURL } = await initPayloadTest({ __dirname, init: { local: false } }); const config = await configPromise; client = new RESTClient(config, { serverURL, defaultSlug: mediaSlug }); await client.login(); }); describe('REST', () => { describe('create', () => { it('creates from form data given a png', async () => { const formData = new FormData(); formData.append('file', fs.createReadStream(path.join(__dirname, './image.png'))); const { status, doc } = await client.create({ file: true, data: formData, auth: true, headers: {}, }); expect(status).toBe(201); // Check for files expect(await fileExists(path.join(__dirname, './media', doc.filename))).toBe(true); expect(await fileExists(path.join(__dirname, './media', doc.sizes.maintainedAspectRatio.filename))).toBe(true); expect(await fileExists(path.join(__dirname, './media', doc.sizes.tablet.filename))).toBe(true); expect(await fileExists(path.join(__dirname, './media', doc.sizes.mobile.filename))).toBe(true); expect(await fileExists(path.join(__dirname, './media', doc.sizes.icon.filename))).toBe(true); // Check api response expect(doc.mimeType).toEqual('image/png'); expect(doc.sizes.maintainedAspectRatio.url).toContain('/media/image'); expect(doc.sizes.maintainedAspectRatio.url).toContain('.png'); expect(doc.sizes.maintainedAspectRatio.width).toEqual(1024); expect(doc.sizes.maintainedAspectRatio.height).toEqual(1024); expect(doc.sizes).toHaveProperty('tablet'); expect(doc.sizes).toHaveProperty('mobile'); expect(doc.sizes).toHaveProperty('icon'); }); it('creates from form data given an svg', async () => { const formData = new FormData(); formData.append('file', fs.createReadStream(path.join(__dirname, './image.svg'))); const { status, doc } = await client.create({ file: true, data: formData, auth: true, headers: {}, }); expect(status).toBe(201); // Check for files expect(await fileExists(path.join(__dirname, './media', doc.filename))).toBe(true); // Check api response expect(doc.mimeType).toEqual('image/svg+xml'); expect(doc.sizes.maintainedAspectRatio.url).toBeUndefined(); expect(doc.width).toBeDefined(); expect(doc.height).toBeDefined(); }); }); it('creates images that do not require all sizes', async () => { const formData = new FormData(); formData.append('file', fs.createReadStream(path.join(__dirname, './small.png'))); const { status, doc } = await client.create({ file: true, data: formData, auth: true, headers: {}, }); expect(status).toBe(201); // Check for files expect(await fileExists(path.join(__dirname, './media', doc.filename))).toBe(true); expect(await fileExists(path.join(__dirname, './media', 'small-640x480.png'))).toBe(false); expect(await fileExists(path.join(__dirname, './media', doc.sizes.icon.filename))).toBe(true); // Check api response expect(doc.sizes.tablet.filename).toBeNull(); expect(doc.sizes.icon.filename).toBeDefined(); }); it('creates images from a different format', async () => { const formData = new FormData(); formData.append('file', fs.createReadStream(path.join(__dirname, './image.jpg'))); const { status, doc } = await client.create({ file: true, data: formData, auth: true, headers: {}, }); expect(status).toBe(201); // Check for files expect(await fileExists(path.join(__dirname, './media', doc.filename))).toBe(true); expect(await fileExists(path.join(__dirname, './media', doc.sizes.tablet.filename))).toBe(true); // Check api response expect(doc.filename).toContain('.png'); expect(doc.mimeType).toEqual('image/png'); expect(doc.sizes.maintainedAspectRatio.filename).toContain('.png'); expect(doc.sizes.maintainedAspectRatio.mimeType).toContain('image/png'); expect(doc.sizes.differentFormatFromMainImage.filename).toContain('.jpg'); expect(doc.sizes.differentFormatFromMainImage.mimeType).toContain('image/jpeg'); }); it('creates media without storing a file', async () => { const formData = new FormData(); formData.append('file', fs.createReadStream(path.join(__dirname, './small.png'))); // unstored media const { status, doc } = await client.create({ slug: 'unstored-media', file: true, data: formData, auth: true, headers: {}, }); expect(status).toBe(201); // Check for files expect(await !fileExists(path.join(__dirname, './media', doc.filename))).toBe(false); // Check api response expect(doc.filename).toBeDefined(); }); }); it('update', async () => { // Create image const filePath = path.resolve(__dirname, './image.png'); const file = await getFileByPath(filePath); file.name = 'renamed.png'; const mediaDoc = await payload.create({ collection: mediaSlug, data: {}, file, }); const formData = new FormData(); formData.append('file', fs.createReadStream(path.join(__dirname, './small.png'))); const { status } = await client.update({ id: mediaDoc.id, file: true, data: formData, auth: true, headers: {}, }); expect(status).toBe(200); // Check that previously existing files were removed expect(await fileExists(path.join(__dirname, './media', mediaDoc.filename))).toBe(true); expect(await fileExists(path.join(__dirname, './media', mediaDoc.sizes.icon.filename))).toBe(true); }); it('update - update many', async () => { // Create image const filePath = path.resolve(__dirname, './image.png'); const file = await getFileByPath(filePath); file.name = 'renamed.png'; const mediaDoc = await payload.create({ collection: mediaSlug, data: {}, file, }); const formData = new FormData(); formData.append('file', fs.createReadStream(path.join(__dirname, './small.png'))); const { status } = await client.updateMany({ // id: mediaDoc.id, where: { id: { equals: mediaDoc.id }, }, file: true, data: formData, auth: true, headers: {}, }); expect(status).toBe(200); // Check that previously existing files were removed expect(await fileExists(path.join(__dirname, './media', mediaDoc.filename))).toBe(true); expect(await fileExists(path.join(__dirname, './media', mediaDoc.sizes.icon.filename))).toBe(true); }); it('should remove existing media on re-upload', async () => { // Create temp file const filePath = path.resolve(__dirname, './temp.png'); const file = await getFileByPath(filePath); file.name = 'temp.png'; const mediaDoc = await payload.create({ collection: mediaSlug, data: {}, file, }); // Check that the temp file was created expect(await fileExists(path.join(__dirname, './media', mediaDoc.filename))).toBe(true); // Replace the temp file with a new one const newFilePath = path.resolve(__dirname, './temp-renamed.png'); const newFile = await getFileByPath(newFilePath); newFile.name = 'temp-renamed.png'; const updatedMediaDoc = await payload.update({ collection: mediaSlug, id: mediaDoc.id, file: newFile, data: {}, }); // Check that the replacement file was created and the old one was removed expect(await fileExists(path.join(__dirname, './media', updatedMediaDoc.filename))).toBe(true); expect(await fileExists(path.join(__dirname, './media', mediaDoc.filename))).toBe(false); }); it('should remove existing media on re-upload - update many', async () => { // Create temp file const filePath = path.resolve(__dirname, './temp.png'); const file = await getFileByPath(filePath); file.name = 'temp.png'; const mediaDoc = await payload.create({ collection: mediaSlug, data: {}, file, }); // Check that the temp file was created expect(await fileExists(path.join(__dirname, './media', mediaDoc.filename))).toBe(true); // Replace the temp file with a new one const newFilePath = path.resolve(__dirname, './temp-renamed.png'); const newFile = await getFileByPath(newFilePath); newFile.name = 'temp-renamed.png'; const updatedMediaDoc = await payload.update({ collection: mediaSlug, where: { id: { equals: mediaDoc.id }, }, file: newFile, data: {}, }); // Check that the replacement file was created and the old one was removed expect(await fileExists(path.join(__dirname, './media', updatedMediaDoc.docs[0].filename))).toBe(true); expect(await fileExists(path.join(__dirname, './media', mediaDoc.filename))).toBe(false); }); it('should remove extra sizes on update', async () => { const filePath = path.resolve(__dirname, './image.png'); const file = await getFileByPath(filePath); const small = await getFileByPath(path.resolve(__dirname, './small.png')); const { id } = await payload.create({ collection: mediaSlug, data: {}, file, }); const doc = await payload.update({ collection: mediaSlug, id, data: {}, file: small, }); expect(doc.sizes.icon).toBeDefined(); expect(doc.sizes.tablet.width).toBeNull(); }); it('should remove extra sizes on update - update many', async () => { const filePath = path.resolve(__dirname, './image.png'); const file = await getFileByPath(filePath); const small = await getFileByPath(path.resolve(__dirname, './small.png')); const { id } = await payload.create({ collection: mediaSlug, data: {}, file, }); const doc = await payload.update({ collection: mediaSlug, where: { id: { equals: id }, }, data: {}, file: small, }); expect(doc.docs[0].sizes.icon).toBeDefined(); expect(doc.docs[0].sizes.tablet.width).toBeNull(); }); it('should allow update removing a relationship', async () => { const filePath = path.resolve(__dirname, './image.png'); const file = await getFileByPath(filePath); file.name = 'renamed.png'; const { id } = await payload.create({ collection: mediaSlug, data: {}, file, }); const related = await payload.create({ collection: relationSlug, data: { image: id, }, }); const doc = await payload.update({ collection: relationSlug, id: related.id, data: { image: null, }, }); expect(doc.image).toBeNull(); }); it('should allow update removing a relationship - update many', async () => { const filePath = path.resolve(__dirname, './image.png'); const file = await getFileByPath(filePath); file.name = 'renamed.png'; const { id } = await payload.create({ collection: mediaSlug, data: {}, file, }); const related = await payload.create({ collection: relationSlug, data: { image: id, }, }); const doc = await payload.update({ collection: relationSlug, where: { id: { equals: related.id }, }, data: { image: null, }, }); expect(doc.docs[0].image).toBeNull(); }); it('delete', async () => { const formData = new FormData(); formData.append('file', fs.createReadStream(path.join(__dirname, './image.png'))); const { doc } = await client.create({ file: true, data: formData, auth: true, headers: {}, }); const { status } = await client.delete(doc.id, { auth: true, }); expect(status).toBe(200); expect(await fileExists(path.join(__dirname, doc.filename))).toBe(false); }); it('delete - update many', async () => { const formData = new FormData(); formData.append('file', fs.createReadStream(path.join(__dirname, './image.png'))); const { doc } = await client.create({ file: true, data: formData, auth: true, headers: {}, }); const { errors } = await client.deleteMany({ slug: mediaSlug, where: { id: { equals: doc.id }, }, auth: true, }); expect(errors).toHaveLength(0); expect(await fileExists(path.join(__dirname, doc.filename))).toBe(false); }); }); async function fileExists(fileName: string): Promise { try { await stat(fileName); return true; } catch (err) { return false; } }