diff --git a/test/helpers/rest.ts b/test/helpers/rest.ts index af30cf52e..ad7340035 100644 --- a/test/helpers/rest.ts +++ b/test/helpers/rest.ts @@ -22,6 +22,7 @@ type CreateArgs = { slug?: string data: T auth?: boolean + file?: boolean } type FindArgs = { @@ -34,8 +35,14 @@ type UpdateArgs = { slug?: string id: string data: Partial + auth?: boolean query?: any } +type DeleteArgs = { + slug?: string + id: string + auth?: boolean +} type DocResponse = { status: number @@ -57,10 +64,10 @@ export class RESTClient { private token: string; - private serverURL: string; - private defaultSlug: string; + serverURL: string; + constructor(config: Config, args: Args) { this.config = config; this.serverURL = args.serverURL; @@ -92,9 +99,9 @@ export class RESTClient { async create(args: CreateArgs): Promise> { const options = { - body: JSON.stringify(args.data), + body: args.file ? args.data : JSON.stringify(args.data), headers: { - ...headers, + ...(args.file ? [] : headers), Authorization: '', }, method: 'post', @@ -138,6 +145,9 @@ export class RESTClient { async update(args: UpdateArgs): Promise> { const { slug, id, data, query } = args; const formattedQs = qs.stringify(query); + if (args?.auth) { + headers.Authorization = `JWT ${this.token}`; + } const response = await fetch( `${this.serverURL}/api/${slug || this.defaultSlug}/${id}${formattedQs}`, { @@ -161,11 +171,20 @@ export class RESTClient { return { status, doc }; } - async delete(id: string, args?: { slug?: string }): Promise> { - const response = await fetch(`${this.serverURL}/api/${args?.slug || this.defaultSlug}/${id}`, { - headers, + async delete(id: string, args?: DeleteArgs): Promise> { + const options = { + headers: { + ...headers, + Authorization: '', + }, method: 'delete', - }); + }; + + if (args?.auth) { + options.headers.Authorization = `JWT ${this.token}`; + } + + const response = await fetch(`${this.serverURL}/api/${args?.slug || this.defaultSlug}/${id}`, options); const { status } = response; const doc = await response.json(); return { status, doc }; diff --git a/test/uploads/config.ts b/test/uploads/config.ts index 9db355caa..50d67f51c 100644 --- a/test/uploads/config.ts +++ b/test/uploads/config.ts @@ -23,7 +23,6 @@ export default buildConfig({ }, }), }, - // upload: {}, collections: [ { slug: relationSlug, @@ -69,6 +68,14 @@ export default buildConfig({ fields: [ ], }, + { + slug: 'unstored-media', + upload: { + staticURL: '/media', + disableLocalStorage: true, + }, + fields: [], + }, ], onInit: async (payload) => { // delete files in /media diff --git a/test/uploads/int.spec.ts b/test/uploads/int.spec.ts index e69de29bb..59e89ae00 100644 --- a/test/uploads/int.spec.ts +++ b/test/uploads/int.spec.ts @@ -0,0 +1,179 @@ +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 config, { mediaSlug } 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 (done) => { + const { serverURL } = await initPayloadTest({ __dirname, init: { local: false } }); + client = new RESTClient(config, { serverURL, defaultSlug: mediaSlug }); + await client.login(); + + done(); + }); + + describe('REST', () => { + describe('create', () => { + it('creates from form data', 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 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).toBeUndefined(); + expect(doc.sizes.icon.filename).toBeDefined(); + }); + + 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 = 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, doc } = await client.update({ + id: mediaDoc.id, + file: true, + data: formData, + auth: true, + headers: {}, + }); + + expect(status).toBe(200); + + // Check that previously existing files weren't affected + 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('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); + }); +}); + +async function fileExists(fileName: string): Promise { + try { + await stat(fileName); + return true; + } catch (err) { + return false; + } +} diff --git a/tests/api/assets/small.png b/test/uploads/small.png similarity index 100% rename from tests/api/assets/small.png rename to test/uploads/small.png