import React from 'react'; import { Image } from 'canvas'; import { fireEvent, render, act } from '@testing-library/react'; import { saveAs } from 'file-saver'; import MemeCreator from './MemeCreator'; async function getCanvasSnapshot(canvas) { const blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/jpeg', 0.5)); const blobText = await new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = (evt) => resolve(evt.target.result); reader.onerror = reject; reader.readAsText(blob); }); return blobText; } jest.mock('./memeTemplates.json', () => [ { value: 'cryingDawson', text: 'Crying Dawson', path: '/memes/dawson.jpg', }, { value: 'jackieChan', text: 'Jackie Chan', path: '/memes/jackie-chan.jpg', }, ]); jest.mock('file-saver', () => ({ saveAs: jest.fn(), })); const RealImage = window.Image; beforeAll(() => { window.Image = Image; }); afterAll(() => { window.Image = RealImage; }); test('renders component correctly', async () => { let getByLabelText; await act(async () => { ({ getByLabelText } = render(<MemeCreator />)); }); const selectElement = getByLabelText(/meme template/i); expect(selectElement).toBeInTheDocument(); const inputElement = getByLabelText(/meme caption/i); expect(inputElement).toBeInTheDocument(); }); test('sets up the canvas on load', async () => { let container; const drawSpy = jest.spyOn(MemeCreator.prototype, 'drawCanvas'); await act(async () => { ({ container } = render(<MemeCreator />)); }); expect(drawSpy).toHaveBeenCalledTimes(1); expect(drawSpy).toHaveBeenCalledWith(expect.any(Image), ''); const canvas = container.querySelector('canvas'); expect(canvas.width).toBe(500); // match dawson.jpg width expect(canvas.height).toBe(451); // match dawson.jpg height const snapshot = await getCanvasSnapshot(canvas); expect(snapshot).toMatchSnapshot(); drawSpy.mockRestore(); }); test('updates the canvas on caption change', async () => { let container; let getByLabelText; const drawSpy = jest.spyOn(MemeCreator.prototype, 'drawCanvas'); await act(async () => { ({ container, getByLabelText } = render(<MemeCreator />)); }); expect(drawSpy).toHaveBeenCalledTimes(1); expect(drawSpy).toHaveBeenLastCalledWith(expect.any(Image), ''); // update caption await act(async () => { const inputElement = getByLabelText(/meme caption/i); fireEvent.change(inputElement, { target: { value: 'Hello' } }); }); expect(drawSpy).toHaveBeenCalledTimes(2); expect(drawSpy).toHaveBeenLastCalledWith(expect.any(Image), 'Hello'); const canvas = container.querySelector('canvas'); expect(canvas.width).toBe(500); // match dawson.jpg width expect(canvas.height).toBe(451); // match dawson.jpg height const snapshot = await getCanvasSnapshot(canvas); expect(snapshot).toMatchSnapshot(); drawSpy.mockRestore(); }); test('updates the canvas when another template is selected', async () => { let container; let getByLabelText; const drawSpy = jest.spyOn(MemeCreator.prototype, 'drawCanvas'); await act(async () => { ({ container, getByLabelText } = render(<MemeCreator />)); }); expect(drawSpy).toHaveBeenCalledTimes(1); expect(drawSpy).toHaveBeenLastCalledWith(expect.any(Image), ''); // update template await act(async () => { const selectElement = getByLabelText(/meme template/i); fireEvent.change(selectElement, { target: { value: 'jackieChan' } }); }); expect(drawSpy).toHaveBeenCalledTimes(2); expect(drawSpy).toHaveBeenLastCalledWith(expect.any(Image), ''); const canvas = container.querySelector('canvas'); expect(canvas.width).toBe(500); // match jackie-chan.jpg width expect(canvas.height).toBe(327); // match jackie-chan.jpg height const snapshot = await getCanvasSnapshot(canvas); expect(snapshot).toMatchSnapshot(); drawSpy.mockRestore(); }); test('triggers a save of the canvas Blob when clicking Download btn', async () => { // set a Promise that resolves when our saveAs mock is called const saveCalled = new Promise((resolve) => { saveAs.mockClear(); saveAs.mockImplementation(resolve); }); let getByText; await act(async () => { ({ getByText } = render(<MemeCreator />)); }); // click Download btn await act(async () => { const dlBtn = getByText(/download/i); fireEvent.click(dlBtn); }); await saveCalled; expect(saveAs).toHaveBeenCalledTimes(1); saveAs.mockImplementation(() => {}); // set mock back to a noop });