import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; import { click, find, render, triggerEvent, waitFor, } from '@ember/test-helpers'; import hbs from 'htmlbars-inline-precompile'; import { ImageUploadSuccessResult } from '@cardstack/web-client/components/image-uploader'; const IMAGE = '[data-test-avatar-image]'; const IMAGE_LOADING = '[data-test-avatar-loading]'; const IMAGE_PLACEHOLDER = '[data-test-avatar-placeholder]'; const UPLOAD_BUTTON = '[data-test-image-uploader-upload-button]'; const DELETE_BUTTON = '[data-test-image-uploader-delete-button]'; const INPUT = '[data-test-image-uploader-file-input]'; const REQUIREMENTS = '[data-test-image-uploader-requirements]'; const ERROR = '[data-test-image-uploader-error]'; let imageDataUri = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='; let image: File; module('Integration | Component | image-uploader', function (hooks) { setupRenderingTest(hooks); hooks.before(async function () { image = await fetch(imageDataUri) .then((res) => res.blob()) .then((blob) => { return new File([blob], 'image.png', { type: 'image/png' }); }); }); hooks.beforeEach(async function () { this.set('image', ''); this.set('onUpload', async (file: ImageUploadSuccessResult) => { this.set('image', file.preview); }); this.set('onError', (e: Error) => { console.error('error uploading image', e); }); this.set('onRemoveImage', () => { this.set('image', ''); }); this.set('cta', 'Select a Photo'); this.set( 'imageRequirements', 'Images must be in jpg or png format at least 50x50, min size 35kb, max 200kb' ); await render(hbs` `); }); test('it can display an image, and a placeholder if there is none', async function (assert) { assert.dom(IMAGE).doesNotExist(); assert.dom(IMAGE_PLACEHOLDER).isVisible(); this.set('image', imageDataUri); assert.dom(IMAGE).hasAttribute('src', imageDataUri); assert.dom(DELETE_BUTTON).isVisible(); }); test('clicking on the cta triggers a click event on the file input', async function (assert) { assert.dom(INPUT).exists(); let input = find(INPUT); let inputTriggered = false; input?.addEventListener('click', (e) => { e.preventDefault(); inputTriggered = true; }); await click(UPLOAD_BUTTON); assert.ok(inputTriggered); }); test('it can upload an image file', async function (assert) { await triggerEvent(find(INPUT)!, 'change', { files: [image], }); await waitFor(IMAGE); assert.dom(IMAGE).hasAttribute('src', imageDataUri); assert.dom(DELETE_BUTTON).isVisible(); }); test('it can trigger deletion of an existing image', async function (assert) { this.set('image', imageDataUri); assert.dom(IMAGE).hasAttribute('src', imageDataUri); assert.dom(DELETE_BUTTON).isVisible(); await click(DELETE_BUTTON); assert.dom(IMAGE).doesNotExist(); }); test('it allows setting of accepted file types', async function (assert) { // assert defaults assert.dom(INPUT).hasAttribute('accept', 'image/jpeg, image/png'); this.set('acceptedFileTypes', 'image/gif'); assert.dom(INPUT).hasAttribute('accept', 'image/gif'); }); test('it displays provided copy', async function (assert) { this.set('image', imageDataUri); assert.dom(UPLOAD_BUTTON).containsText('Select a Photo'); assert .dom(REQUIREMENTS) .containsText( 'Images must be in jpg or png format at least 50x50, min size 35kb, max 200kb' ); this.set( 'imageRequirements', 'No requirements, feel free to upload anything!' ); this.set('cta', 'Set an image identity'); assert.dom(UPLOAD_BUTTON).containsText('Set an image identity'); assert .dom(REQUIREMENTS) .containsText('No requirements, feel free to upload anything!'); }); test('it allows modifying of its preview avatar via the default block', async function (assert) { this.set('rounded', false); this.set('image', imageDataUri); this.set('imageDescription', 'Profile'); this.set('state', 'default'); await render(hbs` `); assert.dom(IMAGE).hasAttribute('src', imageDataUri); assert.dom(IMAGE).hasAttribute('alt', 'Profile'); assert.dom(IMAGE_LOADING).doesNotExist(); assert .dom('[data-test-image-uploader-preview]') .doesNotHaveClass(/--rounded/); this.set('rounded', true); assert.dom('[data-test-image-uploader-preview]').hasClass(/--rounded/); this.set('state', 'loading'); assert.dom(IMAGE_LOADING).isVisible(); }); test('it can represent an error state', async function (assert) { this.set('state', 'default'); await render(hbs` `); assert.dom(ERROR).doesNotExist(); this.set('state', 'error'); assert.dom(ERROR).containsText('This is an error'); }); });