mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-27 13:47:58 +01:00
Switch jest unit tests to vitest (#243)
* Switch jest unit tests to vitest * Cleanup vite config after debugging
This commit is contained in:
parent
dd8c2c81d9
commit
2417f40d37
23 changed files with 1341 additions and 3203 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -59,5 +59,5 @@ npm-debug.log
|
||||||
/native/**/target
|
/native/**/target
|
||||||
/.cargo
|
/.cargo
|
||||||
|
|
||||||
# Jest coverage
|
# Vitest coverage
|
||||||
/assets/coverage
|
/assets/coverage
|
||||||
|
|
|
@ -1,3 +1,2 @@
|
||||||
js/vendor/*
|
js/vendor/*
|
||||||
vite.config.ts
|
vite.config.ts
|
||||||
jest.config.js
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ parserOptions:
|
||||||
|
|
||||||
plugins:
|
plugins:
|
||||||
- '@typescript-eslint'
|
- '@typescript-eslint'
|
||||||
- jest
|
- vitest
|
||||||
|
|
||||||
globals:
|
globals:
|
||||||
ga: false
|
ga: false
|
||||||
|
@ -276,12 +276,14 @@ overrides:
|
||||||
'@typescript-eslint/no-extra-parens': 2
|
'@typescript-eslint/no-extra-parens': 2
|
||||||
no-shadow: 0
|
no-shadow: 0
|
||||||
'@typescript-eslint/no-shadow': 2
|
'@typescript-eslint/no-shadow': 2
|
||||||
# Jest Tests (also written in TypeScript)
|
# Unit Tests (also written in TypeScript)
|
||||||
# Disable rules that do not make sense in test files (e.g. testing for undefined input values should be allowed)
|
# Disable rules that do not make sense in test files (e.g. testing for undefined input values should be allowed)
|
||||||
- files:
|
- files:
|
||||||
- '*.spec.ts'
|
- '*.spec.ts'
|
||||||
- 'test/*.ts'
|
- 'test/*.ts'
|
||||||
extends:
|
extends:
|
||||||
- 'plugin:jest/recommended'
|
- 'plugin:vitest/legacy-recommended'
|
||||||
rules:
|
rules:
|
||||||
no-undefined: 0
|
no-undefined: 0
|
||||||
|
no-unused-expressions: 0
|
||||||
|
vitest/valid-expect: 0
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
import JSDOMEnvironment from 'jest-environment-jsdom';
|
|
||||||
|
|
||||||
export default class FixJSDOMEnvironment extends JSDOMEnvironment {
|
|
||||||
constructor(...args: ConstructorParameters<typeof JSDOMEnvironment>) {
|
|
||||||
super(...args);
|
|
||||||
|
|
||||||
// https://github.com/jsdom/jsdom/issues/1721#issuecomment-1484202038
|
|
||||||
// jsdom URL and Blob are missing most of the implementation
|
|
||||||
// Use the node version of these types instead
|
|
||||||
this.global.URL = URL;
|
|
||||||
this.global.Blob = Blob;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
export default {
|
|
||||||
collectCoverage: true,
|
|
||||||
collectCoverageFrom: [
|
|
||||||
'js/**/*.{js,ts}',
|
|
||||||
],
|
|
||||||
coveragePathIgnorePatterns: [
|
|
||||||
'/node_modules/',
|
|
||||||
'/.*\\.test\\.ts$',
|
|
||||||
'.*\\.d\\.ts$',
|
|
||||||
],
|
|
||||||
coverageDirectory: '<rootDir>/coverage/',
|
|
||||||
coverageThreshold: {
|
|
||||||
global: {
|
|
||||||
statements: 0,
|
|
||||||
branches: 0,
|
|
||||||
functions: 0,
|
|
||||||
lines: 0,
|
|
||||||
},
|
|
||||||
'./js/utils/**/*.ts': {
|
|
||||||
statements: 100,
|
|
||||||
branches: 100,
|
|
||||||
functions: 100,
|
|
||||||
lines: 100,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
preset: 'ts-jest/presets/js-with-ts-esm',
|
|
||||||
setupFilesAfterEnv: ['<rootDir>/test/jest-setup.ts'],
|
|
||||||
testEnvironment: './fix-jsdom.ts',
|
|
||||||
testPathIgnorePatterns: ['/node_modules/', '/dist/'],
|
|
||||||
moduleNameMapper: {
|
|
||||||
'./js/(.*)': '<rootDir>/js/$1',
|
|
||||||
},
|
|
||||||
transform: {
|
|
||||||
'^.+\\.tsx?$': ['ts-jest', {
|
|
||||||
tsconfig: '<rootDir>/tsconfig.json',
|
|
||||||
useESM: true,
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
globals: {
|
|
||||||
extensionsToTreatAsEsm: ['.ts', '.js'],
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { inputDuplicatorCreator } from '../input-duplicator';
|
import { inputDuplicatorCreator } from '../input-duplicator';
|
||||||
import { assertNotNull } from '../utils/assert';
|
import { assertNotNull } from '../utils/assert';
|
||||||
import { $, $$, removeEl } from '../utils/dom';
|
import { $, $$, removeEl } from '../utils/dom';
|
||||||
|
import { fireEvent } from '@testing-library/dom';
|
||||||
|
|
||||||
describe('Input duplicator functionality', () => {
|
describe('Input duplicator functionality', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -41,7 +42,7 @@ describe('Input duplicator functionality', () => {
|
||||||
|
|
||||||
expect($$('input')).toHaveLength(1);
|
expect($$('input')).toHaveLength(1);
|
||||||
|
|
||||||
assertNotNull($<HTMLButtonElement>('.js-add-input')).click();
|
fireEvent.click(assertNotNull($<HTMLButtonElement>('.js-add-input')));
|
||||||
|
|
||||||
expect($$('input')).toHaveLength(2);
|
expect($$('input')).toHaveLength(2);
|
||||||
});
|
});
|
||||||
|
@ -53,7 +54,7 @@ describe('Input duplicator functionality', () => {
|
||||||
form.insertAdjacentElement('afterbegin', buttonDiv);
|
form.insertAdjacentElement('afterbegin', buttonDiv);
|
||||||
runCreator();
|
runCreator();
|
||||||
|
|
||||||
assertNotNull($<HTMLButtonElement>('.js-add-input')).click();
|
fireEvent.click(assertNotNull($<HTMLButtonElement>('.js-add-input')));
|
||||||
|
|
||||||
expect($$('input')).toHaveLength(2);
|
expect($$('input')).toHaveLength(2);
|
||||||
});
|
});
|
||||||
|
@ -62,7 +63,7 @@ describe('Input duplicator functionality', () => {
|
||||||
runCreator();
|
runCreator();
|
||||||
|
|
||||||
for (let i = 0; i < 5; i += 1) {
|
for (let i = 0; i < 5; i += 1) {
|
||||||
assertNotNull($<HTMLButtonElement>('.js-add-input')).click();
|
fireEvent.click(assertNotNull($<HTMLButtonElement>('.js-add-input')));
|
||||||
}
|
}
|
||||||
|
|
||||||
expect($$('input')).toHaveLength(3);
|
expect($$('input')).toHaveLength(3);
|
||||||
|
@ -71,8 +72,8 @@ describe('Input duplicator functionality', () => {
|
||||||
it('should remove duplicated input elements', () => {
|
it('should remove duplicated input elements', () => {
|
||||||
runCreator();
|
runCreator();
|
||||||
|
|
||||||
assertNotNull($<HTMLButtonElement>('.js-add-input')).click();
|
fireEvent.click(assertNotNull($<HTMLButtonElement>('.js-add-input')));
|
||||||
assertNotNull($<HTMLAnchorElement>('.js-remove-input')).click();
|
fireEvent.click(assertNotNull($<HTMLAnchorElement>('.js-remove-input')));
|
||||||
|
|
||||||
expect($$('input')).toHaveLength(1);
|
expect($$('input')).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
@ -80,10 +81,10 @@ describe('Input duplicator functionality', () => {
|
||||||
it('should not remove the last input element', () => {
|
it('should not remove the last input element', () => {
|
||||||
runCreator();
|
runCreator();
|
||||||
|
|
||||||
assertNotNull($<HTMLAnchorElement>('.js-remove-input')).click();
|
fireEvent.click(assertNotNull($<HTMLAnchorElement>('.js-remove-input')));
|
||||||
assertNotNull($<HTMLAnchorElement>('.js-remove-input')).click();
|
fireEvent.click(assertNotNull($<HTMLAnchorElement>('.js-remove-input')));
|
||||||
for (let i = 0; i < 5; i += 1) {
|
for (let i = 0; i < 5; i += 1) {
|
||||||
assertNotNull($<HTMLAnchorElement>('.js-remove-input')).click();
|
fireEvent.click(assertNotNull($<HTMLAnchorElement>('.js-remove-input')));
|
||||||
}
|
}
|
||||||
|
|
||||||
expect($$('input')).toHaveLength(1);
|
expect($$('input')).toHaveLength(1);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import fetchMock from 'jest-fetch-mock';
|
|
||||||
import { fireEvent, waitFor } from '@testing-library/dom';
|
import { fireEvent, waitFor } from '@testing-library/dom';
|
||||||
import { assertType } from '../utils/assert';
|
import { assertType } from '../utils/assert';
|
||||||
import '../ujs';
|
import '../ujs';
|
||||||
|
import { fetchMock } from '../../test/fetch-mock';
|
||||||
|
|
||||||
const mockEndpoint = 'http://localhost/endpoint';
|
const mockEndpoint = 'http://localhost/endpoint';
|
||||||
const mockVerb = 'POST';
|
const mockVerb = 'POST';
|
||||||
|
@ -38,7 +38,7 @@ describe('Remote utilities', () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
document.documentElement.insertAdjacentElement('beforeend', a);
|
document.documentElement.insertAdjacentElement('beforeend', a);
|
||||||
a.click();
|
fireEvent.click(a, { button: 0 });
|
||||||
|
|
||||||
return a;
|
return a;
|
||||||
};
|
};
|
||||||
|
@ -88,7 +88,7 @@ describe('Remote utilities', () => {
|
||||||
a.dataset.method = mockVerb;
|
a.dataset.method = mockVerb;
|
||||||
|
|
||||||
document.documentElement.insertAdjacentElement('beforeend', a);
|
document.documentElement.insertAdjacentElement('beforeend', a);
|
||||||
a.click();
|
fireEvent.click(a);
|
||||||
|
|
||||||
return a;
|
return a;
|
||||||
};
|
};
|
||||||
|
@ -128,7 +128,7 @@ describe('Remote utilities', () => {
|
||||||
...Object.getOwnPropertyDescriptors(oldWindowLocation),
|
...Object.getOwnPropertyDescriptors(oldWindowLocation),
|
||||||
reload: {
|
reload: {
|
||||||
configurable: true,
|
configurable: true,
|
||||||
value: jest.fn(),
|
value: vi.fn(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -155,7 +155,7 @@ describe('Remote utilities', () => {
|
||||||
const submitForm = () => {
|
const submitForm = () => {
|
||||||
const form = configureForm();
|
const form = configureForm();
|
||||||
form.method = mockVerb;
|
form.method = mockVerb;
|
||||||
form.submit();
|
fireEvent.submit(form);
|
||||||
return form;
|
return form;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -176,7 +176,7 @@ describe('Remote utilities', () => {
|
||||||
it('should submit a PUT request with put data-method specified', () => {
|
it('should submit a PUT request with put data-method specified', () => {
|
||||||
const form = configureForm();
|
const form = configureForm();
|
||||||
form.dataset.method = 'put';
|
form.dataset.method = 'put';
|
||||||
form.submit();
|
fireEvent.submit(form);
|
||||||
expect(fetch).toHaveBeenCalledTimes(1);
|
expect(fetch).toHaveBeenCalledTimes(1);
|
||||||
expect(fetch).toHaveBeenNthCalledWith(1, mockEndpoint, {
|
expect(fetch).toHaveBeenNthCalledWith(1, mockEndpoint, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
|
@ -201,7 +201,7 @@ describe('Remote utilities', () => {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should reload the page on 300 multiple choices response', () => {
|
it('should reload the page on 300 multiple choices response', () => {
|
||||||
jest.spyOn(global, 'fetch').mockResolvedValue(new Response('', { status: 300}));
|
vi.spyOn(global, 'fetch').mockResolvedValue(new Response('', { status: 300}));
|
||||||
|
|
||||||
submitForm();
|
submitForm();
|
||||||
return waitFor(() => expect(window.location.reload).toHaveBeenCalledTimes(1));
|
return waitFor(() => expect(window.location.reload).toHaveBeenCalledTimes(1));
|
||||||
|
@ -211,28 +211,29 @@ describe('Remote utilities', () => {
|
||||||
|
|
||||||
describe('Form utilities', () => {
|
describe('Form utilities', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.spyOn(window, 'requestAnimationFrame').mockImplementation(cb => {
|
vi.spyOn(window, 'requestAnimationFrame').mockImplementation(cb => {
|
||||||
cb(1);
|
cb(1);
|
||||||
return 1;
|
return 1;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('[data-confirm]', () => {
|
describe('[data-confirm]', () => {
|
||||||
const createA = () => {
|
const createA = () => {
|
||||||
const a = document.createElement('a');
|
const a = document.createElement('a');
|
||||||
a.dataset.confirm = 'confirm';
|
a.dataset.confirm = 'confirm';
|
||||||
a.href = mockEndpoint;
|
// We cannot use mockEndpoint here since anything except a hash change will log an error in the test output
|
||||||
|
a.href = '#hash';
|
||||||
document.documentElement.insertAdjacentElement('beforeend', a);
|
document.documentElement.insertAdjacentElement('beforeend', a);
|
||||||
return a;
|
return a;
|
||||||
};
|
};
|
||||||
|
|
||||||
it('should cancel the event on failed confirm', () => {
|
it('should cancel the event on failed confirm', () => {
|
||||||
const a = createA();
|
const a = createA();
|
||||||
const confirm = jest.spyOn(window, 'confirm').mockImplementationOnce(() => false);
|
const confirm = vi.spyOn(window, 'confirm').mockImplementationOnce(() => false);
|
||||||
const event = new MouseEvent('click', { bubbles: true, cancelable: true });
|
const event = new MouseEvent('click', { bubbles: true, cancelable: true });
|
||||||
|
|
||||||
expect(fireEvent(a, event)).toBe(false);
|
expect(fireEvent(a, event)).toBe(false);
|
||||||
|
@ -241,7 +242,7 @@ describe('Form utilities', () => {
|
||||||
|
|
||||||
it('should allow the event on confirm', () => {
|
it('should allow the event on confirm', () => {
|
||||||
const a = createA();
|
const a = createA();
|
||||||
const confirm = jest.spyOn(window, 'confirm').mockImplementationOnce(() => true);
|
const confirm = vi.spyOn(window, 'confirm').mockImplementationOnce(() => true);
|
||||||
const event = new MouseEvent('click', { bubbles: true, cancelable: true });
|
const event = new MouseEvent('click', { bubbles: true, cancelable: true });
|
||||||
|
|
||||||
expect(fireEvent(a, event)).toBe(true);
|
expect(fireEvent(a, event)).toBe(true);
|
||||||
|
@ -276,7 +277,7 @@ describe('Form utilities', () => {
|
||||||
|
|
||||||
it('should disable submit button containing a text child on click', () => {
|
it('should disable submit button containing a text child on click', () => {
|
||||||
const [ , button ] = createFormAndButton(submitText, loadingText);
|
const [ , button ] = createFormAndButton(submitText, loadingText);
|
||||||
button.click();
|
fireEvent.click(button);
|
||||||
|
|
||||||
expect(button.textContent).toEqual(' Loading...');
|
expect(button.textContent).toEqual(' Loading...');
|
||||||
expect(button.dataset.enableWith).toEqual(submitText);
|
expect(button.dataset.enableWith).toEqual(submitText);
|
||||||
|
@ -284,7 +285,7 @@ describe('Form utilities', () => {
|
||||||
|
|
||||||
it('should disable submit button containing element children on click', () => {
|
it('should disable submit button containing element children on click', () => {
|
||||||
const [ , button ] = createFormAndButton(submitMarkup, loadingMarkup);
|
const [ , button ] = createFormAndButton(submitMarkup, loadingMarkup);
|
||||||
button.click();
|
fireEvent.click(button);
|
||||||
|
|
||||||
expect(button.innerHTML).toEqual(loadingMarkup);
|
expect(button.innerHTML).toEqual(loadingMarkup);
|
||||||
expect(button.dataset.enableWith).toEqual(submitMarkup);
|
expect(button.dataset.enableWith).toEqual(submitMarkup);
|
||||||
|
@ -293,7 +294,7 @@ describe('Form utilities', () => {
|
||||||
it('should not disable anything when the form is invalid', () => {
|
it('should not disable anything when the form is invalid', () => {
|
||||||
const [ form, button ] = createFormAndButton(submitText, loadingText);
|
const [ form, button ] = createFormAndButton(submitText, loadingText);
|
||||||
form.insertAdjacentHTML('afterbegin', '<input type="text" name="valid" required="true" />');
|
form.insertAdjacentHTML('afterbegin', '<input type="text" name="valid" required="true" />');
|
||||||
button.click();
|
fireEvent.click(button);
|
||||||
|
|
||||||
expect(button.textContent).toEqual(submitText);
|
expect(button.textContent).toEqual(submitText);
|
||||||
expect(button.dataset.enableWith).not.toBeDefined();
|
expect(button.dataset.enableWith).not.toBeDefined();
|
||||||
|
@ -301,7 +302,7 @@ describe('Form utilities', () => {
|
||||||
|
|
||||||
it('should reset submit button containing a text child on completion', () => {
|
it('should reset submit button containing a text child on completion', () => {
|
||||||
const [ form, button ] = createFormAndButton(submitText, loadingText);
|
const [ form, button ] = createFormAndButton(submitText, loadingText);
|
||||||
button.click();
|
fireEvent.click(button);
|
||||||
fireEvent(form, new CustomEvent('reset', { bubbles: true }));
|
fireEvent(form, new CustomEvent('reset', { bubbles: true }));
|
||||||
|
|
||||||
expect(button.textContent?.trim()).toEqual(submitText);
|
expect(button.textContent?.trim()).toEqual(submitText);
|
||||||
|
@ -310,7 +311,7 @@ describe('Form utilities', () => {
|
||||||
|
|
||||||
it('should reset submit button containing element children on completion', () => {
|
it('should reset submit button containing element children on completion', () => {
|
||||||
const [ form, button ] = createFormAndButton(submitMarkup, loadingMarkup);
|
const [ form, button ] = createFormAndButton(submitMarkup, loadingMarkup);
|
||||||
button.click();
|
fireEvent.click(button);
|
||||||
fireEvent(form, new CustomEvent('reset', { bubbles: true }));
|
fireEvent(form, new CustomEvent('reset', { bubbles: true }));
|
||||||
|
|
||||||
expect(button.innerHTML).toEqual(submitMarkup);
|
expect(button.innerHTML).toEqual(submitMarkup);
|
||||||
|
@ -319,7 +320,7 @@ describe('Form utilities', () => {
|
||||||
|
|
||||||
it('should reset disabled form elements on pageshow', () => {
|
it('should reset disabled form elements on pageshow', () => {
|
||||||
const [ , button ] = createFormAndButton(submitText, loadingText);
|
const [ , button ] = createFormAndButton(submitText, loadingText);
|
||||||
button.click();
|
fireEvent.click(button);
|
||||||
fireEvent(window, new CustomEvent('pageshow'));
|
fireEvent(window, new CustomEvent('pageshow'));
|
||||||
|
|
||||||
expect(button.textContent?.trim()).toEqual(submitText);
|
expect(button.textContent?.trim()).toEqual(submitText);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { $, $$, removeEl } from '../utils/dom';
|
import { $, $$, removeEl } from '../utils/dom';
|
||||||
import { assertNotNull, assertNotUndefined } from '../utils/assert';
|
import { assertNotNull, assertNotUndefined } from '../utils/assert';
|
||||||
|
|
||||||
import fetchMock from 'jest-fetch-mock';
|
import { fetchMock } from '../../test/fetch-mock';
|
||||||
import { fixEventListeners } from '../../test/fix-event-listeners';
|
import { fixEventListeners } from '../../test/fix-event-listeners';
|
||||||
import { fireEvent, waitFor } from '@testing-library/dom';
|
import { fireEvent, waitFor } from '@testing-library/dom';
|
||||||
import { promises } from 'fs';
|
import { promises } from 'fs';
|
||||||
|
@ -47,6 +47,7 @@ describe('Image upload form', () => {
|
||||||
|
|
||||||
fixEventListeners(window);
|
fixEventListeners(window);
|
||||||
|
|
||||||
|
|
||||||
let form: HTMLFormElement;
|
let form: HTMLFormElement;
|
||||||
let imgPreviews: HTMLDivElement;
|
let imgPreviews: HTMLDivElement;
|
||||||
let fileField: HTMLInputElement;
|
let fileField: HTMLInputElement;
|
||||||
|
@ -57,6 +58,10 @@ describe('Image upload form', () => {
|
||||||
let sourceEl: HTMLInputElement;
|
let sourceEl: HTMLInputElement;
|
||||||
let descrEl: HTMLTextAreaElement;
|
let descrEl: HTMLTextAreaElement;
|
||||||
|
|
||||||
|
const assertFetchButtonIsDisabled = () => {
|
||||||
|
if (!fetchButton.hasAttribute('disabled')) throw new Error('fetchButton is not disabled');
|
||||||
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
document.documentElement.insertAdjacentHTML('beforeend', `
|
document.documentElement.insertAdjacentHTML('beforeend', `
|
||||||
<form action="/images">
|
<form action="/images">
|
||||||
|
@ -102,17 +107,26 @@ describe('Image upload form', () => {
|
||||||
|
|
||||||
it('should create a preview element when an image file is uploaded', () => {
|
it('should create a preview element when an image file is uploaded', () => {
|
||||||
fireEvent.change(fileField, { target: { files: [mockPng] } });
|
fireEvent.change(fileField, { target: { files: [mockPng] } });
|
||||||
return waitFor(() => expect(imgPreviews.querySelectorAll('img')).toHaveLength(1));
|
return waitFor(() => {
|
||||||
|
assertFetchButtonIsDisabled();
|
||||||
|
expect(imgPreviews.querySelectorAll('img')).toHaveLength(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create a preview element when a Matroska video file is uploaded', () => {
|
it('should create a preview element when a Matroska video file is uploaded', () => {
|
||||||
fireEvent.change(fileField, { target: { files: [mockWebm] } });
|
fireEvent.change(fileField, { target: { files: [mockWebm] } });
|
||||||
return waitFor(() => expect(imgPreviews.querySelectorAll('video')).toHaveLength(1));
|
return waitFor(() => {
|
||||||
|
assertFetchButtonIsDisabled();
|
||||||
|
expect(imgPreviews.querySelectorAll('video')).toHaveLength(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should block navigation away after an image file is attached, but not after form submission', async() => {
|
it('should block navigation away after an image file is attached, but not after form submission', async() => {
|
||||||
fireEvent.change(fileField, { target: { files: [mockPng] } });
|
fireEvent.change(fileField, { target: { files: [mockPng] } });
|
||||||
await waitFor(() => { expect(imgPreviews.querySelectorAll('img')).toHaveLength(1); });
|
await waitFor(() => {
|
||||||
|
assertFetchButtonIsDisabled();
|
||||||
|
expect(imgPreviews.querySelectorAll('img')).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
const failedUnloadEvent = new Event('beforeunload', { cancelable: true });
|
const failedUnloadEvent = new Event('beforeunload', { cancelable: true });
|
||||||
expect(fireEvent(window, failedUnloadEvent)).toBe(false);
|
expect(fireEvent(window, failedUnloadEvent)).toBe(false);
|
||||||
|
@ -122,7 +136,7 @@ describe('Image upload form', () => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
form.submit();
|
fireEvent.submit(form);
|
||||||
});
|
});
|
||||||
|
|
||||||
const succeededUnloadEvent = new Event('beforeunload', { cancelable: true });
|
const succeededUnloadEvent = new Event('beforeunload', { cancelable: true });
|
||||||
|
@ -154,7 +168,7 @@ describe('Image upload form', () => {
|
||||||
fetchMock.mockResolvedValue(new Response(JSON.stringify(nullResponse), { status: 200 }));
|
fetchMock.mockResolvedValue(new Response(JSON.stringify(nullResponse), { status: 200 }));
|
||||||
|
|
||||||
fireEvent.input(remoteUrl, { target: { value: 'http://localhost/images/1' } });
|
fireEvent.input(remoteUrl, { target: { value: 'http://localhost/images/1' } });
|
||||||
fetchButton.click();
|
fireEvent.click(fetchButton);
|
||||||
|
|
||||||
return waitFor(() => {
|
return waitFor(() => {
|
||||||
expect(fetch).toHaveBeenCalledTimes(1);
|
expect(fetch).toHaveBeenCalledTimes(1);
|
||||||
|
@ -167,7 +181,7 @@ describe('Image upload form', () => {
|
||||||
fetchMock.mockResolvedValue(new Response(JSON.stringify(errorResponse), { status: 200 }));
|
fetchMock.mockResolvedValue(new Response(JSON.stringify(errorResponse), { status: 200 }));
|
||||||
|
|
||||||
fireEvent.input(remoteUrl, { target: { value: 'http://localhost/images/1' } });
|
fireEvent.input(remoteUrl, { target: { value: 'http://localhost/images/1' } });
|
||||||
fetchButton.click();
|
fireEvent.click(fetchButton);
|
||||||
|
|
||||||
return waitFor(() => {
|
return waitFor(() => {
|
||||||
expect(fetch).toHaveBeenCalledTimes(1);
|
expect(fetch).toHaveBeenCalledTimes(1);
|
||||||
|
|
|
@ -29,11 +29,11 @@ describe('DOM Utilities', () => {
|
||||||
|
|
||||||
describe('$', () => {
|
describe('$', () => {
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.restoreAllMocks();
|
vi.restoreAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call the native querySelector method on document by default', () => {
|
it('should call the native querySelector method on document by default', () => {
|
||||||
const spy = jest.spyOn(document, 'querySelector');
|
const spy = vi.spyOn(document, 'querySelector');
|
||||||
|
|
||||||
mockSelectors.forEach((selector, nthCall) => {
|
mockSelectors.forEach((selector, nthCall) => {
|
||||||
$(selector);
|
$(selector);
|
||||||
|
@ -43,7 +43,7 @@ describe('DOM Utilities', () => {
|
||||||
|
|
||||||
it('should call the native querySelector method on the passed element', () => {
|
it('should call the native querySelector method on the passed element', () => {
|
||||||
const mockElement = document.createElement('br');
|
const mockElement = document.createElement('br');
|
||||||
const spy = jest.spyOn(mockElement, 'querySelector');
|
const spy = vi.spyOn(mockElement, 'querySelector');
|
||||||
|
|
||||||
mockSelectors.forEach((selector, nthCall) => {
|
mockSelectors.forEach((selector, nthCall) => {
|
||||||
// FIXME This will not be necessary once the file is properly typed
|
// FIXME This will not be necessary once the file is properly typed
|
||||||
|
@ -55,11 +55,11 @@ describe('DOM Utilities', () => {
|
||||||
|
|
||||||
describe('$$', () => {
|
describe('$$', () => {
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.restoreAllMocks();
|
vi.restoreAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call the native querySelectorAll method on document by default', () => {
|
it('should call the native querySelectorAll method on document by default', () => {
|
||||||
const spy = jest.spyOn(document, 'querySelectorAll');
|
const spy = vi.spyOn(document, 'querySelectorAll');
|
||||||
|
|
||||||
mockSelectors.forEach((selector, nthCall) => {
|
mockSelectors.forEach((selector, nthCall) => {
|
||||||
$$(selector);
|
$$(selector);
|
||||||
|
@ -69,7 +69,7 @@ describe('DOM Utilities', () => {
|
||||||
|
|
||||||
it('should call the native querySelectorAll method on the passed element', () => {
|
it('should call the native querySelectorAll method on the passed element', () => {
|
||||||
const mockElement = document.createElement('br');
|
const mockElement = document.createElement('br');
|
||||||
const spy = jest.spyOn(mockElement, 'querySelectorAll');
|
const spy = vi.spyOn(mockElement, 'querySelectorAll');
|
||||||
|
|
||||||
mockSelectors.forEach((selector, nthCall) => {
|
mockSelectors.forEach((selector, nthCall) => {
|
||||||
// FIXME This will not be necessary once the file is properly typed
|
// FIXME This will not be necessary once the file is properly typed
|
||||||
|
@ -83,7 +83,7 @@ describe('DOM Utilities', () => {
|
||||||
it(`should remove the ${hiddenClass} class from the provided element`, () => {
|
it(`should remove the ${hiddenClass} class from the provided element`, () => {
|
||||||
const mockElement = createHiddenElement('div');
|
const mockElement = createHiddenElement('div');
|
||||||
showEl(mockElement);
|
showEl(mockElement);
|
||||||
expect(mockElement).not.toHaveClass(hiddenClass);
|
expect(mockElement).not.to.have.class(hiddenClass);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should remove the ${hiddenClass} class from all provided elements`, () => {
|
it(`should remove the ${hiddenClass} class from all provided elements`, () => {
|
||||||
|
@ -93,9 +93,9 @@ describe('DOM Utilities', () => {
|
||||||
createHiddenElement('strong'),
|
createHiddenElement('strong'),
|
||||||
];
|
];
|
||||||
showEl(mockElements);
|
showEl(mockElements);
|
||||||
expect(mockElements[0]).not.toHaveClass(hiddenClass);
|
expect(mockElements[0]).not.to.have.class(hiddenClass);
|
||||||
expect(mockElements[1]).not.toHaveClass(hiddenClass);
|
expect(mockElements[1]).not.to.have.class(hiddenClass);
|
||||||
expect(mockElements[2]).not.toHaveClass(hiddenClass);
|
expect(mockElements[2]).not.to.have.class(hiddenClass);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should remove the ${hiddenClass} class from elements provided in multiple arrays`, () => {
|
it(`should remove the ${hiddenClass} class from elements provided in multiple arrays`, () => {
|
||||||
|
@ -108,10 +108,10 @@ describe('DOM Utilities', () => {
|
||||||
createHiddenElement('em'),
|
createHiddenElement('em'),
|
||||||
];
|
];
|
||||||
showEl(mockElements1, mockElements2);
|
showEl(mockElements1, mockElements2);
|
||||||
expect(mockElements1[0]).not.toHaveClass(hiddenClass);
|
expect(mockElements1[0]).not.to.have.class(hiddenClass);
|
||||||
expect(mockElements1[1]).not.toHaveClass(hiddenClass);
|
expect(mockElements1[1]).not.to.have.class(hiddenClass);
|
||||||
expect(mockElements2[0]).not.toHaveClass(hiddenClass);
|
expect(mockElements2[0]).not.to.have.class(hiddenClass);
|
||||||
expect(mockElements2[1]).not.toHaveClass(hiddenClass);
|
expect(mockElements2[1]).not.to.have.class(hiddenClass);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ describe('DOM Utilities', () => {
|
||||||
it(`should add the ${hiddenClass} class to the provided element`, () => {
|
it(`should add the ${hiddenClass} class to the provided element`, () => {
|
||||||
const mockElement = document.createElement('div');
|
const mockElement = document.createElement('div');
|
||||||
hideEl(mockElement);
|
hideEl(mockElement);
|
||||||
expect(mockElement).toHaveClass(hiddenClass);
|
expect(mockElement).to.have.class(hiddenClass);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should add the ${hiddenClass} class to all provided elements`, () => {
|
it(`should add the ${hiddenClass} class to all provided elements`, () => {
|
||||||
|
@ -129,9 +129,9 @@ describe('DOM Utilities', () => {
|
||||||
document.createElement('strong'),
|
document.createElement('strong'),
|
||||||
];
|
];
|
||||||
hideEl(mockElements);
|
hideEl(mockElements);
|
||||||
expect(mockElements[0]).toHaveClass(hiddenClass);
|
expect(mockElements[0]).to.have.class(hiddenClass);
|
||||||
expect(mockElements[1]).toHaveClass(hiddenClass);
|
expect(mockElements[1]).to.have.class(hiddenClass);
|
||||||
expect(mockElements[2]).toHaveClass(hiddenClass);
|
expect(mockElements[2]).to.have.class(hiddenClass);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should add the ${hiddenClass} class to elements provided in multiple arrays`, () => {
|
it(`should add the ${hiddenClass} class to elements provided in multiple arrays`, () => {
|
||||||
|
@ -144,10 +144,10 @@ describe('DOM Utilities', () => {
|
||||||
document.createElement('em'),
|
document.createElement('em'),
|
||||||
];
|
];
|
||||||
hideEl(mockElements1, mockElements2);
|
hideEl(mockElements1, mockElements2);
|
||||||
expect(mockElements1[0]).toHaveClass(hiddenClass);
|
expect(mockElements1[0]).to.have.class(hiddenClass);
|
||||||
expect(mockElements1[1]).toHaveClass(hiddenClass);
|
expect(mockElements1[1]).to.have.class(hiddenClass);
|
||||||
expect(mockElements2[0]).toHaveClass(hiddenClass);
|
expect(mockElements2[0]).to.have.class(hiddenClass);
|
||||||
expect(mockElements2[1]).toHaveClass(hiddenClass);
|
expect(mockElements2[1]).to.have.class(hiddenClass);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ describe('DOM Utilities', () => {
|
||||||
it('should set the disabled attribute to true', () => {
|
it('should set the disabled attribute to true', () => {
|
||||||
const mockElement = document.createElement('button');
|
const mockElement = document.createElement('button');
|
||||||
disableEl(mockElement);
|
disableEl(mockElement);
|
||||||
expect(mockElement).toBeDisabled();
|
expect(mockElement).to.have.property('disabled', true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set the disabled attribute to true on all provided elements', () => {
|
it('should set the disabled attribute to true on all provided elements', () => {
|
||||||
|
@ -164,8 +164,8 @@ describe('DOM Utilities', () => {
|
||||||
document.createElement('button'),
|
document.createElement('button'),
|
||||||
];
|
];
|
||||||
disableEl(mockElements);
|
disableEl(mockElements);
|
||||||
expect(mockElements[0]).toBeDisabled();
|
expect(mockElements[0]).to.have.property('disabled', true);
|
||||||
expect(mockElements[1]).toBeDisabled();
|
expect(mockElements[1]).to.have.property('disabled', true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set the disabled attribute to true on elements provided in multiple arrays', () => {
|
it('should set the disabled attribute to true on elements provided in multiple arrays', () => {
|
||||||
|
@ -178,10 +178,10 @@ describe('DOM Utilities', () => {
|
||||||
document.createElement('button'),
|
document.createElement('button'),
|
||||||
];
|
];
|
||||||
disableEl(mockElements1, mockElements2);
|
disableEl(mockElements1, mockElements2);
|
||||||
expect(mockElements1[0]).toBeDisabled();
|
expect(mockElements1[0]).to.have.property('disabled', true);
|
||||||
expect(mockElements1[1]).toBeDisabled();
|
expect(mockElements1[1]).to.have.property('disabled', true);
|
||||||
expect(mockElements2[0]).toBeDisabled();
|
expect(mockElements2[0]).to.have.property('disabled', true);
|
||||||
expect(mockElements2[1]).toBeDisabled();
|
expect(mockElements2[1]).to.have.property('disabled', true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -189,7 +189,7 @@ describe('DOM Utilities', () => {
|
||||||
it('should set the disabled attribute to false', () => {
|
it('should set the disabled attribute to false', () => {
|
||||||
const mockElement = document.createElement('button');
|
const mockElement = document.createElement('button');
|
||||||
enableEl(mockElement);
|
enableEl(mockElement);
|
||||||
expect(mockElement).toBeEnabled();
|
expect(mockElement).to.have.property('disabled', false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set the disabled attribute to false on all provided elements', () => {
|
it('should set the disabled attribute to false on all provided elements', () => {
|
||||||
|
@ -198,8 +198,8 @@ describe('DOM Utilities', () => {
|
||||||
document.createElement('button'),
|
document.createElement('button'),
|
||||||
];
|
];
|
||||||
enableEl(mockElements);
|
enableEl(mockElements);
|
||||||
expect(mockElements[0]).toBeEnabled();
|
expect(mockElements[0]).to.have.property('disabled', false);
|
||||||
expect(mockElements[1]).toBeEnabled();
|
expect(mockElements[1]).to.have.property('disabled', false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set the disabled attribute to false on elements provided in multiple arrays', () => {
|
it('should set the disabled attribute to false on elements provided in multiple arrays', () => {
|
||||||
|
@ -212,10 +212,10 @@ describe('DOM Utilities', () => {
|
||||||
document.createElement('button'),
|
document.createElement('button'),
|
||||||
];
|
];
|
||||||
enableEl(mockElements1, mockElements2);
|
enableEl(mockElements1, mockElements2);
|
||||||
expect(mockElements1[0]).toBeEnabled();
|
expect(mockElements1[0]).to.have.property('disabled', false);
|
||||||
expect(mockElements1[1]).toBeEnabled();
|
expect(mockElements1[1]).to.have.property('disabled', false);
|
||||||
expect(mockElements2[0]).toBeEnabled();
|
expect(mockElements2[0]).to.have.property('disabled', false);
|
||||||
expect(mockElements2[1]).toBeEnabled();
|
expect(mockElements2[1]).to.have.property('disabled', false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -223,11 +223,11 @@ describe('DOM Utilities', () => {
|
||||||
it(`should toggle the ${hiddenClass} class on the provided element`, () => {
|
it(`should toggle the ${hiddenClass} class on the provided element`, () => {
|
||||||
const mockVisibleElement = document.createElement('div');
|
const mockVisibleElement = document.createElement('div');
|
||||||
toggleEl(mockVisibleElement);
|
toggleEl(mockVisibleElement);
|
||||||
expect(mockVisibleElement).toHaveClass(hiddenClass);
|
expect(mockVisibleElement).to.have.class(hiddenClass);
|
||||||
|
|
||||||
const mockHiddenElement = createHiddenElement('div');
|
const mockHiddenElement = createHiddenElement('div');
|
||||||
toggleEl(mockHiddenElement);
|
toggleEl(mockHiddenElement);
|
||||||
expect(mockHiddenElement).not.toHaveClass(hiddenClass);
|
expect(mockHiddenElement).not.to.have.class(hiddenClass);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should toggle the ${hiddenClass} class on all provided elements`, () => {
|
it(`should toggle the ${hiddenClass} class on all provided elements`, () => {
|
||||||
|
@ -238,10 +238,10 @@ describe('DOM Utilities', () => {
|
||||||
createHiddenElement('em'),
|
createHiddenElement('em'),
|
||||||
];
|
];
|
||||||
toggleEl(mockElements);
|
toggleEl(mockElements);
|
||||||
expect(mockElements[0]).toHaveClass(hiddenClass);
|
expect(mockElements[0]).to.have.class(hiddenClass);
|
||||||
expect(mockElements[1]).not.toHaveClass(hiddenClass);
|
expect(mockElements[1]).not.to.have.class(hiddenClass);
|
||||||
expect(mockElements[2]).toHaveClass(hiddenClass);
|
expect(mockElements[2]).to.have.class(hiddenClass);
|
||||||
expect(mockElements[3]).not.toHaveClass(hiddenClass);
|
expect(mockElements[3]).not.to.have.class(hiddenClass);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should toggle the ${hiddenClass} class on elements provided in multiple arrays`, () => {
|
it(`should toggle the ${hiddenClass} class on elements provided in multiple arrays`, () => {
|
||||||
|
@ -254,10 +254,10 @@ describe('DOM Utilities', () => {
|
||||||
document.createElement('em'),
|
document.createElement('em'),
|
||||||
];
|
];
|
||||||
toggleEl(mockElements1, mockElements2);
|
toggleEl(mockElements1, mockElements2);
|
||||||
expect(mockElements1[0]).not.toHaveClass(hiddenClass);
|
expect(mockElements1[0]).not.to.have.class(hiddenClass);
|
||||||
expect(mockElements1[1]).toHaveClass(hiddenClass);
|
expect(mockElements1[1]).to.have.class(hiddenClass);
|
||||||
expect(mockElements2[0]).not.toHaveClass(hiddenClass);
|
expect(mockElements2[0]).not.to.have.class(hiddenClass);
|
||||||
expect(mockElements2[1]).toHaveClass(hiddenClass);
|
expect(mockElements2[1]).to.have.class(hiddenClass);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -311,7 +311,7 @@ describe('DOM Utilities', () => {
|
||||||
|
|
||||||
describe('removeEl', () => {
|
describe('removeEl', () => {
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.restoreAllMocks();
|
vi.restoreAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should NOT throw error if element has no parent', () => {
|
it('should NOT throw error if element has no parent', () => {
|
||||||
|
@ -324,7 +324,7 @@ describe('DOM Utilities', () => {
|
||||||
const childNode = document.createElement('p');
|
const childNode = document.createElement('p');
|
||||||
parentNode.appendChild(childNode);
|
parentNode.appendChild(childNode);
|
||||||
|
|
||||||
const spy = jest.spyOn(parentNode, 'removeChild');
|
const spy = vi.spyOn(parentNode, 'removeChild');
|
||||||
|
|
||||||
removeEl(childNode);
|
removeEl(childNode);
|
||||||
expect(spy).toHaveBeenCalledTimes(1);
|
expect(spy).toHaveBeenCalledTimes(1);
|
||||||
|
@ -361,8 +361,8 @@ describe('DOM Utilities', () => {
|
||||||
const mockClassTwo = 'class-two';
|
const mockClassTwo = 'class-two';
|
||||||
const el = makeEl('p', { className: `${mockClassOne} ${mockClassTwo}` });
|
const el = makeEl('p', { className: `${mockClassOne} ${mockClassTwo}` });
|
||||||
expect(el.nodeName).toEqual('P');
|
expect(el.nodeName).toEqual('P');
|
||||||
expect(el).toHaveClass(mockClassOne);
|
expect(el).to.have.class(mockClassOne);
|
||||||
expect(el).toHaveClass(mockClassTwo);
|
expect(el).to.have.class(mockClassTwo);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -374,7 +374,7 @@ describe('DOM Utilities', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call callback on left click', () => {
|
it('should call callback on left click', () => {
|
||||||
const mockCallback = jest.fn();
|
const mockCallback = vi.fn();
|
||||||
const element = document.createElement('div');
|
const element = document.createElement('div');
|
||||||
cleanup = onLeftClick(mockCallback, element as unknown as Document);
|
cleanup = onLeftClick(mockCallback, element as unknown as Document);
|
||||||
|
|
||||||
|
@ -384,7 +384,7 @@ describe('DOM Utilities', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should NOT call callback on non-left click', () => {
|
it('should NOT call callback on non-left click', () => {
|
||||||
const mockCallback = jest.fn();
|
const mockCallback = vi.fn();
|
||||||
const element = document.createElement('div');
|
const element = document.createElement('div');
|
||||||
cleanup = onLeftClick(mockCallback, element as unknown as Document);
|
cleanup = onLeftClick(mockCallback, element as unknown as Document);
|
||||||
|
|
||||||
|
@ -395,7 +395,7 @@ describe('DOM Utilities', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add click event listener to the document by default', () => {
|
it('should add click event listener to the document by default', () => {
|
||||||
const mockCallback = jest.fn();
|
const mockCallback = vi.fn();
|
||||||
cleanup = onLeftClick(mockCallback);
|
cleanup = onLeftClick(mockCallback);
|
||||||
|
|
||||||
fireEvent.click(document.body);
|
fireEvent.click(document.body);
|
||||||
|
@ -404,7 +404,7 @@ describe('DOM Utilities', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return a cleanup function that removes the listener', () => {
|
it('should return a cleanup function that removes the listener', () => {
|
||||||
const mockCallback = jest.fn();
|
const mockCallback = vi.fn();
|
||||||
const element = document.createElement('div');
|
const element = document.createElement('div');
|
||||||
const localCleanup = onLeftClick(mockCallback, element as unknown as Document);
|
const localCleanup = onLeftClick(mockCallback, element as unknown as Document);
|
||||||
|
|
||||||
|
@ -424,8 +424,8 @@ describe('DOM Utilities', () => {
|
||||||
describe('whenReady', () => {
|
describe('whenReady', () => {
|
||||||
it('should call callback immediately if document ready state is not loading', () => {
|
it('should call callback immediately if document ready state is not loading', () => {
|
||||||
const mockReadyStateValue = getRandomArrayItem<DocumentReadyState>(['complete', 'interactive']);
|
const mockReadyStateValue = getRandomArrayItem<DocumentReadyState>(['complete', 'interactive']);
|
||||||
const readyStateSpy = jest.spyOn(document, 'readyState', 'get').mockReturnValue(mockReadyStateValue);
|
const readyStateSpy = vi.spyOn(document, 'readyState', 'get').mockReturnValue(mockReadyStateValue);
|
||||||
const mockCallback = jest.fn();
|
const mockCallback = vi.fn();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
whenReady(mockCallback);
|
whenReady(mockCallback);
|
||||||
|
@ -437,9 +437,9 @@ describe('DOM Utilities', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add event listener with callback if document ready state is loading', () => {
|
it('should add event listener with callback if document ready state is loading', () => {
|
||||||
const readyStateSpy = jest.spyOn(document, 'readyState', 'get').mockReturnValue('loading');
|
const readyStateSpy = vi.spyOn(document, 'readyState', 'get').mockReturnValue('loading');
|
||||||
const addEventListenerSpy = jest.spyOn(document, 'addEventListener');
|
const addEventListenerSpy = vi.spyOn(document, 'addEventListener');
|
||||||
const mockCallback = jest.fn();
|
const mockCallback = vi.fn();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
whenReady(mockCallback);
|
whenReady(mockCallback);
|
||||||
|
|
|
@ -30,7 +30,7 @@ describe('Draggable Utilities', () => {
|
||||||
const draggingClass = 'dragging';
|
const draggingClass = 'dragging';
|
||||||
const dragContainerClass = 'drag-container';
|
const dragContainerClass = 'drag-container';
|
||||||
const dragOverClass = 'over';
|
const dragOverClass = 'over';
|
||||||
let documentEventListenerSpy: jest.SpyInstance;
|
let documentEventListenerSpy: MockInstance;
|
||||||
|
|
||||||
let mockDragContainer: HTMLDivElement;
|
let mockDragContainer: HTMLDivElement;
|
||||||
let mockDraggable: HTMLDivElement;
|
let mockDraggable: HTMLDivElement;
|
||||||
|
@ -45,7 +45,7 @@ describe('Draggable Utilities', () => {
|
||||||
|
|
||||||
|
|
||||||
// Redirect all document event listeners to this element for easier cleanup
|
// Redirect all document event listeners to this element for easier cleanup
|
||||||
documentEventListenerSpy = jest.spyOn(document, 'addEventListener').mockImplementation((...params) => {
|
documentEventListenerSpy = vi.spyOn(document, 'addEventListener').mockImplementation((...params) => {
|
||||||
mockDragContainer.addEventListener(...params);
|
mockDragContainer.addEventListener(...params);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -63,7 +63,7 @@ describe('Draggable Utilities', () => {
|
||||||
|
|
||||||
fireEvent(mockDraggable, mockEvent);
|
fireEvent(mockDraggable, mockEvent);
|
||||||
|
|
||||||
expect(mockDraggable).toHaveClass(draggingClass);
|
expect(mockDraggable).to.have.class(draggingClass);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add dummy data to the dragstart event if it\'s empty', () => {
|
it('should add dummy data to the dragstart event if it\'s empty', () => {
|
||||||
|
@ -146,7 +146,7 @@ describe('Draggable Utilities', () => {
|
||||||
|
|
||||||
fireEvent(mockDraggable, mockEvent);
|
fireEvent(mockDraggable, mockEvent);
|
||||||
|
|
||||||
expect(mockDraggable).toHaveClass(dragOverClass);
|
expect(mockDraggable).to.have.class(dragOverClass);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -159,7 +159,7 @@ describe('Draggable Utilities', () => {
|
||||||
|
|
||||||
fireEvent(mockDraggable, mockEvent);
|
fireEvent(mockDraggable, mockEvent);
|
||||||
|
|
||||||
expect(mockDraggable).not.toHaveClass(dragOverClass);
|
expect(mockDraggable).not.to.have.class(dragOverClass);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -170,13 +170,13 @@ describe('Draggable Utilities', () => {
|
||||||
const mockStartEvent = createDragEvent('dragstart');
|
const mockStartEvent = createDragEvent('dragstart');
|
||||||
fireEvent(mockDraggable, mockStartEvent);
|
fireEvent(mockDraggable, mockStartEvent);
|
||||||
|
|
||||||
expect(mockDraggable).toHaveClass(draggingClass);
|
expect(mockDraggable).to.have.class(draggingClass);
|
||||||
|
|
||||||
const mockDropEvent = createDragEvent('drop');
|
const mockDropEvent = createDragEvent('drop');
|
||||||
fireEvent(mockDraggable, mockDropEvent);
|
fireEvent(mockDraggable, mockDropEvent);
|
||||||
|
|
||||||
expect(mockDropEvent.defaultPrevented).toBe(true);
|
expect(mockDropEvent.defaultPrevented).toBe(true);
|
||||||
expect(mockDraggable).not.toHaveClass(draggingClass);
|
expect(mockDraggable).not.to.have.class(draggingClass);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should cancel the event and insert source before target if dropped on left side', () => {
|
it('should cancel the event and insert source before target if dropped on left side', () => {
|
||||||
|
@ -188,11 +188,11 @@ describe('Draggable Utilities', () => {
|
||||||
const mockStartEvent = createDragEvent('dragstart');
|
const mockStartEvent = createDragEvent('dragstart');
|
||||||
fireEvent(mockSecondDraggable, mockStartEvent);
|
fireEvent(mockSecondDraggable, mockStartEvent);
|
||||||
|
|
||||||
expect(mockSecondDraggable).toHaveClass(draggingClass);
|
expect(mockSecondDraggable).to.have.class(draggingClass);
|
||||||
|
|
||||||
const mockDropEvent = createDragEvent('drop');
|
const mockDropEvent = createDragEvent('drop');
|
||||||
Object.assign(mockDropEvent, { clientX: 124 });
|
Object.assign(mockDropEvent, { clientX: 124 });
|
||||||
const boundingBoxSpy = jest.spyOn(mockDraggable, 'getBoundingClientRect').mockReturnValue({
|
const boundingBoxSpy = vi.spyOn(mockDraggable, 'getBoundingClientRect').mockReturnValue({
|
||||||
left: 100,
|
left: 100,
|
||||||
width: 50,
|
width: 50,
|
||||||
} as unknown as DOMRect);
|
} as unknown as DOMRect);
|
||||||
|
@ -200,7 +200,7 @@ describe('Draggable Utilities', () => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
expect(mockDropEvent.defaultPrevented).toBe(true);
|
expect(mockDropEvent.defaultPrevented).toBe(true);
|
||||||
expect(mockSecondDraggable).not.toHaveClass(draggingClass);
|
expect(mockSecondDraggable).not.to.have.class(draggingClass);
|
||||||
expect(mockSecondDraggable.nextElementSibling).toBe(mockDraggable);
|
expect(mockSecondDraggable.nextElementSibling).toBe(mockDraggable);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -217,11 +217,11 @@ describe('Draggable Utilities', () => {
|
||||||
const mockStartEvent = createDragEvent('dragstart');
|
const mockStartEvent = createDragEvent('dragstart');
|
||||||
fireEvent(mockSecondDraggable, mockStartEvent);
|
fireEvent(mockSecondDraggable, mockStartEvent);
|
||||||
|
|
||||||
expect(mockSecondDraggable).toHaveClass(draggingClass);
|
expect(mockSecondDraggable).to.have.class(draggingClass);
|
||||||
|
|
||||||
const mockDropEvent = createDragEvent('drop');
|
const mockDropEvent = createDragEvent('drop');
|
||||||
Object.assign(mockDropEvent, { clientX: 125 });
|
Object.assign(mockDropEvent, { clientX: 125 });
|
||||||
const boundingBoxSpy = jest.spyOn(mockDraggable, 'getBoundingClientRect').mockReturnValue({
|
const boundingBoxSpy = vi.spyOn(mockDraggable, 'getBoundingClientRect').mockReturnValue({
|
||||||
left: 100,
|
left: 100,
|
||||||
width: 50,
|
width: 50,
|
||||||
} as unknown as DOMRect);
|
} as unknown as DOMRect);
|
||||||
|
@ -229,7 +229,7 @@ describe('Draggable Utilities', () => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
expect(mockDropEvent.defaultPrevented).toBe(true);
|
expect(mockDropEvent.defaultPrevented).toBe(true);
|
||||||
expect(mockSecondDraggable).not.toHaveClass(draggingClass);
|
expect(mockSecondDraggable).not.to.have.class(draggingClass);
|
||||||
expect(mockDraggable.nextElementSibling).toBe(mockSecondDraggable);
|
expect(mockDraggable.nextElementSibling).toBe(mockSecondDraggable);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -259,7 +259,7 @@ describe('Draggable Utilities', () => {
|
||||||
const mockStartEvent = createDragEvent('dragstart');
|
const mockStartEvent = createDragEvent('dragstart');
|
||||||
fireEvent(mockDraggable, mockStartEvent);
|
fireEvent(mockDraggable, mockStartEvent);
|
||||||
|
|
||||||
expect(mockDraggable).toHaveClass(draggingClass);
|
expect(mockDraggable).to.have.class(draggingClass);
|
||||||
|
|
||||||
const mockOverElement = createDraggableElement();
|
const mockOverElement = createDraggableElement();
|
||||||
mockOverElement.classList.add(dragOverClass);
|
mockOverElement.classList.add(dragOverClass);
|
||||||
|
@ -270,8 +270,8 @@ describe('Draggable Utilities', () => {
|
||||||
const mockDropEvent = createDragEvent('dragend');
|
const mockDropEvent = createDragEvent('dragend');
|
||||||
fireEvent(mockDraggable, mockDropEvent);
|
fireEvent(mockDraggable, mockDropEvent);
|
||||||
|
|
||||||
expect(mockDraggable).not.toHaveClass(draggingClass);
|
expect(mockDraggable).not.to.have.class(draggingClass);
|
||||||
expect(mockOverElement).not.toHaveClass(dragOverClass);
|
expect(mockOverElement).not.to.have.class(dragOverClass);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -291,7 +291,7 @@ describe('Draggable Utilities', () => {
|
||||||
initDraggables();
|
initDraggables();
|
||||||
|
|
||||||
const mockEvent = createDragEvent('dragstart');
|
const mockEvent = createDragEvent('dragstart');
|
||||||
const draggableClosestSpy = jest.spyOn(mockDraggable, 'closest').mockReturnValue(null);
|
const draggableClosestSpy = vi.spyOn(mockDraggable, 'closest').mockReturnValue(null);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
fireEvent(mockDraggable, mockEvent);
|
fireEvent(mockDraggable, mockEvent);
|
||||||
|
|
|
@ -8,7 +8,7 @@ describe('Event utils', () => {
|
||||||
describe('fire', () => {
|
describe('fire', () => {
|
||||||
it('should call the native dispatchEvent method on the element', () => {
|
it('should call the native dispatchEvent method on the element', () => {
|
||||||
const mockElement = document.createElement('div');
|
const mockElement = document.createElement('div');
|
||||||
const dispatchEventSpy = jest.spyOn(mockElement, 'dispatchEvent');
|
const dispatchEventSpy = vi.spyOn(mockElement, 'dispatchEvent');
|
||||||
const mockDetail = getRandomArrayItem([0, 'test', null]);
|
const mockDetail = getRandomArrayItem([0, 'test', null]);
|
||||||
|
|
||||||
fire(mockElement, mockEvent, mockDetail);
|
fire(mockElement, mockEvent, mockDetail);
|
||||||
|
@ -42,7 +42,7 @@ describe('Event utils', () => {
|
||||||
mockButton.classList.add('mock-button');
|
mockButton.classList.add('mock-button');
|
||||||
mockInnerElement.appendChild(mockButton);
|
mockInnerElement.appendChild(mockButton);
|
||||||
|
|
||||||
const mockHandler = jest.fn();
|
const mockHandler = vi.fn();
|
||||||
on(mockElement, 'click', `.${innerClass}`, mockHandler);
|
on(mockElement, 'click', `.${innerClass}`, mockHandler);
|
||||||
|
|
||||||
fireEvent(mockButton, new Event('click', { bubbles: true }));
|
fireEvent(mockButton, new Event('click', { bubbles: true }));
|
||||||
|
@ -58,7 +58,7 @@ describe('Event utils', () => {
|
||||||
describe('leftClick', () => {
|
describe('leftClick', () => {
|
||||||
it('should fire on left click', () => {
|
it('should fire on left click', () => {
|
||||||
const mockButton = document.createElement('button');
|
const mockButton = document.createElement('button');
|
||||||
const mockHandler = jest.fn();
|
const mockHandler = vi.fn();
|
||||||
|
|
||||||
mockButton.addEventListener('click', e => leftClick(mockHandler)(e, mockButton));
|
mockButton.addEventListener('click', e => leftClick(mockHandler)(e, mockButton));
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ describe('Event utils', () => {
|
||||||
|
|
||||||
it('should NOT fire on any other click', () => {
|
it('should NOT fire on any other click', () => {
|
||||||
const mockButton = document.createElement('button');
|
const mockButton = document.createElement('button');
|
||||||
const mockHandler = jest.fn();
|
const mockHandler = vi.fn();
|
||||||
const mockButtonNumber = getRandomArrayItem([1, 2, 3, 4, 5]);
|
const mockButtonNumber = getRandomArrayItem([1, 2, 3, 4, 5]);
|
||||||
|
|
||||||
mockButton.addEventListener('click', e => leftClick(mockHandler)(e, mockButton));
|
mockButton.addEventListener('click', e => leftClick(mockHandler)(e, mockButton));
|
||||||
|
@ -83,7 +83,7 @@ describe('Event utils', () => {
|
||||||
describe('delegate', () => {
|
describe('delegate', () => {
|
||||||
it('should call the native addEventListener method on the element', () => {
|
it('should call the native addEventListener method on the element', () => {
|
||||||
const mockElement = document.createElement('div');
|
const mockElement = document.createElement('div');
|
||||||
const addEventListenerSpy = jest.spyOn(mockElement, 'addEventListener');
|
const addEventListenerSpy = vi.spyOn(mockElement, 'addEventListener');
|
||||||
|
|
||||||
delegate(mockElement, mockEvent, {});
|
delegate(mockElement, mockEvent, {});
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ describe('Event utils', () => {
|
||||||
const mockButton = document.createElement('button');
|
const mockButton = document.createElement('button');
|
||||||
mockElement.appendChild(mockButton);
|
mockElement.appendChild(mockButton);
|
||||||
|
|
||||||
const mockHandler = jest.fn();
|
const mockHandler = vi.fn();
|
||||||
delegate(mockElement, 'click', { [`.${parentClass}`]: mockHandler });
|
delegate(mockElement, 'click', { [`.${parentClass}`]: mockHandler });
|
||||||
|
|
||||||
fireEvent(mockButton, new Event('click', { bubbles: true }));
|
fireEvent(mockButton, new Event('click', { bubbles: true }));
|
||||||
|
@ -127,8 +127,8 @@ describe('Event utils', () => {
|
||||||
const mockButton = document.createElement('button');
|
const mockButton = document.createElement('button');
|
||||||
mockWrapperElement.appendChild(mockButton);
|
mockWrapperElement.appendChild(mockButton);
|
||||||
|
|
||||||
const mockParentHandler = jest.fn();
|
const mockParentHandler = vi.fn();
|
||||||
const mockWrapperHandler = jest.fn().mockReturnValue(false);
|
const mockWrapperHandler = vi.fn().mockReturnValue(false);
|
||||||
delegate(mockElement, 'click', {
|
delegate(mockElement, 'click', {
|
||||||
[`.${wrapperClass}`]: mockWrapperHandler,
|
[`.${wrapperClass}`]: mockWrapperHandler,
|
||||||
[`.${parentClass}`]: mockParentHandler,
|
[`.${parentClass}`]: mockParentHandler,
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { mockStorage } from '../../../test/mock-storage';
|
||||||
import { createEvent, fireEvent } from '@testing-library/dom';
|
import { createEvent, fireEvent } from '@testing-library/dom';
|
||||||
import { EventType } from '@testing-library/dom/types/events';
|
import { EventType } from '@testing-library/dom/types/events';
|
||||||
import { SpoilerType } from '../../../types/booru-object';
|
import { SpoilerType } from '../../../types/booru-object';
|
||||||
|
import { beforeEach } from 'vitest';
|
||||||
|
|
||||||
describe('Image utils', () => {
|
describe('Image utils', () => {
|
||||||
const hiddenClass = 'hidden';
|
const hiddenClass = 'hidden';
|
||||||
|
@ -82,6 +83,10 @@ describe('Image utils', () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mockServeHidpiValue = null;
|
||||||
|
});
|
||||||
|
|
||||||
describe('video thumbnail', () => {
|
describe('video thumbnail', () => {
|
||||||
type CreateMockElementsOptions = {
|
type CreateMockElementsOptions = {
|
||||||
extension: string;
|
extension: string;
|
||||||
|
@ -109,7 +114,7 @@ describe('Image utils', () => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
mockElement.appendChild(mockVideo);
|
mockElement.appendChild(mockVideo);
|
||||||
const playSpy = jest.spyOn(mockVideo, 'play').mockReturnValue(Promise.resolve());
|
const playSpy = vi.spyOn(mockVideo, 'play').mockReturnValue(Promise.resolve());
|
||||||
|
|
||||||
const mockSpoilerOverlay = createMockSpoilerOverlay();
|
const mockSpoilerOverlay = createMockSpoilerOverlay();
|
||||||
mockElement.appendChild(mockSpoilerOverlay);
|
mockElement.appendChild(mockSpoilerOverlay);
|
||||||
|
@ -141,7 +146,7 @@ describe('Image utils', () => {
|
||||||
|
|
||||||
const result = showThumb(mockElement);
|
const result = showThumb(mockElement);
|
||||||
|
|
||||||
expect(mockImage).toHaveClass(hiddenClass);
|
expect(mockImage).to.have.class(hiddenClass);
|
||||||
expect(mockVideo.children).toHaveLength(2);
|
expect(mockVideo.children).toHaveLength(2);
|
||||||
|
|
||||||
const webmSourceElement = mockVideo.children[0];
|
const webmSourceElement = mockVideo.children[0];
|
||||||
|
@ -155,10 +160,10 @@ describe('Image utils', () => {
|
||||||
expect(mp4SourceElement.getAttribute('type')).toEqual('video/mp4');
|
expect(mp4SourceElement.getAttribute('type')).toEqual('video/mp4');
|
||||||
expect(mp4SourceElement.getAttribute('src')).toEqual(webmSource.replace('webm', 'mp4'));
|
expect(mp4SourceElement.getAttribute('src')).toEqual(webmSource.replace('webm', 'mp4'));
|
||||||
|
|
||||||
expect(mockVideo).not.toHaveClass(hiddenClass);
|
expect(mockVideo).not.to.have.class(hiddenClass);
|
||||||
expect(playSpy).toHaveBeenCalledTimes(1);
|
expect(playSpy).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
expect(mockSpoilerOverlay).toHaveClass(hiddenClass);
|
expect(mockSpoilerOverlay).to.have.class(hiddenClass);
|
||||||
|
|
||||||
expect(result).toBe(true);
|
expect(result).toBe(true);
|
||||||
});
|
});
|
||||||
|
@ -168,7 +173,7 @@ describe('Image utils', () => {
|
||||||
const { mockElement } = createMockElements({
|
const { mockElement } = createMockElements({
|
||||||
extension: 'webm',
|
extension: 'webm',
|
||||||
});
|
});
|
||||||
const jsonParseSpy = jest.spyOn(JSON, 'parse');
|
const jsonParseSpy = vi.spyOn(JSON, 'parse');
|
||||||
|
|
||||||
mockElement.removeAttribute(missingAttributeName);
|
mockElement.removeAttribute(missingAttributeName);
|
||||||
|
|
||||||
|
@ -233,7 +238,7 @@ describe('Image utils', () => {
|
||||||
expect(mockSizeImage.src).toBe(mockSizeUrls[mockSize]);
|
expect(mockSizeImage.src).toBe(mockSizeUrls[mockSize]);
|
||||||
expect(mockSizeImage.srcset).toBe('');
|
expect(mockSizeImage.srcset).toBe('');
|
||||||
|
|
||||||
expect(mockSpoilerOverlay).toHaveClass(hiddenClass);
|
expect(mockSpoilerOverlay).to.have.class(hiddenClass);
|
||||||
expect(result).toBe(true);
|
expect(result).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -250,7 +255,7 @@ describe('Image utils', () => {
|
||||||
expect(mockSizeImage.src).toBe(mockSizeUrls[mockSize]);
|
expect(mockSizeImage.src).toBe(mockSizeUrls[mockSize]);
|
||||||
expect(mockSizeImage.srcset).toBe('');
|
expect(mockSizeImage.srcset).toBe('');
|
||||||
|
|
||||||
expect(mockSpoilerOverlay).toHaveClass(hiddenClass);
|
expect(mockSpoilerOverlay).to.have.class(hiddenClass);
|
||||||
expect(result).toBe(true);
|
expect(result).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -267,8 +272,8 @@ describe('Image utils', () => {
|
||||||
expect(mockSizeImage.src).toBe(mockSizeUrls[mockSize].replace('webm', 'gif'));
|
expect(mockSizeImage.src).toBe(mockSizeUrls[mockSize].replace('webm', 'gif'));
|
||||||
expect(mockSizeImage.srcset).toBe('');
|
expect(mockSizeImage.srcset).toBe('');
|
||||||
|
|
||||||
expect(mockSpoilerOverlay).not.toHaveClass(hiddenClass);
|
expect(mockSpoilerOverlay).not.to.have.class(hiddenClass);
|
||||||
expect(mockSpoilerOverlay).toHaveTextContent('WebM');
|
expect(mockSpoilerOverlay).to.have.text('WebM');
|
||||||
|
|
||||||
expect(result).toBe(true);
|
expect(result).toBe(true);
|
||||||
});
|
});
|
||||||
|
@ -291,7 +296,7 @@ describe('Image utils', () => {
|
||||||
expect(mockSizeImage.srcset).toContain(`${mockSizeUrls[size]} 1x`);
|
expect(mockSizeImage.srcset).toContain(`${mockSizeUrls[size]} 1x`);
|
||||||
expect(mockSizeImage.srcset).toContain(`${mockSizeUrls[x2size]} 2x`);
|
expect(mockSizeImage.srcset).toContain(`${mockSizeUrls[x2size]} 2x`);
|
||||||
|
|
||||||
expect(mockSpoilerOverlay).toHaveClass(hiddenClass);
|
expect(mockSpoilerOverlay).to.have.class(hiddenClass);
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -318,7 +323,7 @@ describe('Image utils', () => {
|
||||||
expect(mockSizeImage.src).toBe(mockSizeUrls[mockSize]);
|
expect(mockSizeImage.src).toBe(mockSizeUrls[mockSize]);
|
||||||
expect(mockSizeImage.srcset).toBe('');
|
expect(mockSizeImage.srcset).toBe('');
|
||||||
|
|
||||||
expect(mockSpoilerOverlay).toHaveClass(hiddenClass);
|
expect(mockSpoilerOverlay).to.have.class(hiddenClass);
|
||||||
expect(result).toBe(true);
|
expect(result).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -359,9 +364,9 @@ describe('Image utils', () => {
|
||||||
|
|
||||||
showBlock(mockElement);
|
showBlock(mockElement);
|
||||||
|
|
||||||
expect(mockFilteredImageElement).toHaveClass(hiddenClass);
|
expect(mockFilteredImageElement).to.have.class(hiddenClass);
|
||||||
expect(mockShowElement).not.toHaveClass(hiddenClass);
|
expect(mockShowElement).not.to.have.class(hiddenClass);
|
||||||
expect(mockShowElement).toHaveClass(spoilerPendingClass);
|
expect(mockShowElement).to.have.class(spoilerPendingClass);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not throw if image-filtered element is missing', () => {
|
it('should not throw if image-filtered element is missing', () => {
|
||||||
|
@ -382,7 +387,7 @@ describe('Image utils', () => {
|
||||||
it('should return early if picture AND video elements are missing', () => {
|
it('should return early if picture AND video elements are missing', () => {
|
||||||
const mockElement = document.createElement('div');
|
const mockElement = document.createElement('div');
|
||||||
|
|
||||||
const querySelectorSpy = jest.spyOn(mockElement, 'querySelector');
|
const querySelectorSpy = vi.spyOn(mockElement, 'querySelector');
|
||||||
|
|
||||||
hideThumb(mockElement, mockSpoilerUri, mockSpoilerReason);
|
hideThumb(mockElement, mockSpoilerUri, mockSpoilerReason);
|
||||||
|
|
||||||
|
@ -399,9 +404,9 @@ describe('Image utils', () => {
|
||||||
const mockElement = document.createElement('div');
|
const mockElement = document.createElement('div');
|
||||||
const mockVideo = document.createElement('video');
|
const mockVideo = document.createElement('video');
|
||||||
mockElement.appendChild(mockVideo);
|
mockElement.appendChild(mockVideo);
|
||||||
const pauseSpy = jest.spyOn(mockVideo, 'pause').mockReturnValue(undefined);
|
const pauseSpy = vi.spyOn(mockVideo, 'pause').mockReturnValue(undefined);
|
||||||
|
|
||||||
const querySelectorSpy = jest.spyOn(mockElement, 'querySelector');
|
const querySelectorSpy = vi.spyOn(mockElement, 'querySelector');
|
||||||
|
|
||||||
hideThumb(mockElement, mockSpoilerUri, mockSpoilerReason);
|
hideThumb(mockElement, mockSpoilerUri, mockSpoilerReason);
|
||||||
|
|
||||||
|
@ -411,7 +416,7 @@ describe('Image utils', () => {
|
||||||
expect(querySelectorSpy).toHaveBeenNthCalledWith(2, 'video');
|
expect(querySelectorSpy).toHaveBeenNthCalledWith(2, 'video');
|
||||||
expect(querySelectorSpy).toHaveBeenNthCalledWith(3, 'img');
|
expect(querySelectorSpy).toHaveBeenNthCalledWith(3, 'img');
|
||||||
expect(querySelectorSpy).toHaveBeenNthCalledWith(4, `.${spoilerOverlayClass}`);
|
expect(querySelectorSpy).toHaveBeenNthCalledWith(4, `.${spoilerOverlayClass}`);
|
||||||
expect(mockVideo).not.toHaveClass(hiddenClass);
|
expect(mockVideo).not.to.have.class(hiddenClass);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
querySelectorSpy.mockRestore();
|
querySelectorSpy.mockRestore();
|
||||||
|
@ -423,7 +428,7 @@ describe('Image utils', () => {
|
||||||
const mockElement = document.createElement('div');
|
const mockElement = document.createElement('div');
|
||||||
const mockVideo = document.createElement('video');
|
const mockVideo = document.createElement('video');
|
||||||
mockElement.appendChild(mockVideo);
|
mockElement.appendChild(mockVideo);
|
||||||
const pauseSpy = jest.spyOn(mockVideo, 'pause').mockReturnValue(undefined);
|
const pauseSpy = vi.spyOn(mockVideo, 'pause').mockReturnValue(undefined);
|
||||||
const mockImage = document.createElement('img');
|
const mockImage = document.createElement('img');
|
||||||
mockImage.classList.add(hiddenClass);
|
mockImage.classList.add(hiddenClass);
|
||||||
mockElement.appendChild(mockImage);
|
mockElement.appendChild(mockImage);
|
||||||
|
@ -434,11 +439,11 @@ describe('Image utils', () => {
|
||||||
hideThumb(mockElement, mockSpoilerUri, mockSpoilerReason);
|
hideThumb(mockElement, mockSpoilerUri, mockSpoilerReason);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
expect(mockImage).not.toHaveClass(hiddenClass);
|
expect(mockImage).not.to.have.class(hiddenClass);
|
||||||
expect(mockImage).toHaveAttribute('src', mockSpoilerUri);
|
expect(mockImage).to.have.attribute('src', mockSpoilerUri);
|
||||||
expect(mockOverlay).toHaveTextContent(mockSpoilerReason);
|
expect(mockOverlay).to.have.text(mockSpoilerReason);
|
||||||
expect(mockVideo).toBeEmptyDOMElement();
|
expect(mockVideo).not.to.have.descendants('*');
|
||||||
expect(mockVideo).toHaveClass(hiddenClass);
|
expect(mockVideo).to.have.class(hiddenClass);
|
||||||
expect(pauseSpy).toHaveBeenCalled();
|
expect(pauseSpy).toHaveBeenCalled();
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -452,8 +457,8 @@ describe('Image utils', () => {
|
||||||
const mockPicture = document.createElement('picture');
|
const mockPicture = document.createElement('picture');
|
||||||
mockElement.appendChild(mockPicture);
|
mockElement.appendChild(mockPicture);
|
||||||
|
|
||||||
const imgQuerySelectorSpy = jest.spyOn(mockElement, 'querySelector');
|
const imgQuerySelectorSpy = vi.spyOn(mockElement, 'querySelector');
|
||||||
const pictureQuerySelectorSpy = jest.spyOn(mockPicture, 'querySelector');
|
const pictureQuerySelectorSpy = vi.spyOn(mockPicture, 'querySelector');
|
||||||
|
|
||||||
hideThumb(mockElement, mockSpoilerUri, mockSpoilerReason);
|
hideThumb(mockElement, mockSpoilerUri, mockSpoilerReason);
|
||||||
|
|
||||||
|
@ -483,24 +488,24 @@ describe('Image utils', () => {
|
||||||
|
|
||||||
hideThumb(mockElement, mockSpoilerUri, mockSpoilerReason);
|
hideThumb(mockElement, mockSpoilerUri, mockSpoilerReason);
|
||||||
|
|
||||||
expect(mockImage).toHaveAttribute('srcset', '');
|
expect(mockImage).to.have.attribute('srcset', '');
|
||||||
expect(mockImage).toHaveAttribute('src', mockSpoilerUri);
|
expect(mockImage).to.have.attribute('src', mockSpoilerUri);
|
||||||
expect(mockOverlay).toContainHTML(mockSpoilerReason);
|
expect(mockOverlay).to.contain.html(mockSpoilerReason);
|
||||||
expect(mockOverlay).not.toHaveClass(hiddenClass);
|
expect(mockOverlay).not.to.have.class(hiddenClass);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('spoilerThumb', () => {
|
describe('spoilerThumb', () => {
|
||||||
const testSpoilerThumb = (handlers?: [EventType, EventType]) => {
|
const testSpoilerThumb = (handlers?: [EventType, EventType]) => {
|
||||||
const { mockElement, mockSpoilerOverlay, mockSizeImage } = createMockElementWithPicture('jpg');
|
const { mockElement, mockSpoilerOverlay, mockSizeImage } = createMockElementWithPicture('jpg');
|
||||||
const addEventListenerSpy = jest.spyOn(mockElement, 'addEventListener');
|
const addEventListenerSpy = vi.spyOn(mockElement, 'addEventListener');
|
||||||
|
|
||||||
spoilerThumb(mockElement, mockSpoilerUri, mockSpoilerReason);
|
spoilerThumb(mockElement, mockSpoilerUri, mockSpoilerReason);
|
||||||
|
|
||||||
// Element should be hidden by the call
|
// Element should be hidden by the call
|
||||||
expect(mockSizeImage).toHaveAttribute('src', mockSpoilerUri);
|
expect(mockSizeImage).to.have.attribute('src', mockSpoilerUri);
|
||||||
expect(mockSpoilerOverlay).not.toHaveClass(hiddenClass);
|
expect(mockSpoilerOverlay).not.to.have.class(hiddenClass);
|
||||||
expect(mockSpoilerOverlay).toContainHTML(mockSpoilerReason);
|
expect(mockSpoilerOverlay).to.contain.html(mockSpoilerReason);
|
||||||
|
|
||||||
// If addEventListener calls are not expected, bail
|
// If addEventListener calls are not expected, bail
|
||||||
if (!handlers) {
|
if (!handlers) {
|
||||||
|
@ -521,8 +526,8 @@ describe('Image utils', () => {
|
||||||
if (firstHandler === 'click') {
|
if (firstHandler === 'click') {
|
||||||
expect(clickEvent.defaultPrevented).toBe(true);
|
expect(clickEvent.defaultPrevented).toBe(true);
|
||||||
}
|
}
|
||||||
expect(mockSizeImage).not.toHaveAttribute('src', mockSpoilerUri);
|
expect(mockSizeImage).not.to.have.attribute('src', mockSpoilerUri);
|
||||||
expect(mockSpoilerOverlay).toHaveClass(hiddenClass);
|
expect(mockSpoilerOverlay).to.have.class(hiddenClass);
|
||||||
|
|
||||||
if (firstHandler === 'click') {
|
if (firstHandler === 'click') {
|
||||||
// Second attempt to click a shown spoiler should not cause default prevention
|
// Second attempt to click a shown spoiler should not cause default prevention
|
||||||
|
@ -534,9 +539,9 @@ describe('Image utils', () => {
|
||||||
// Moving the mouse away should hide the image and show the overlay again
|
// Moving the mouse away should hide the image and show the overlay again
|
||||||
const mouseLeaveEvent = createEvent.mouseLeave(mockElement);
|
const mouseLeaveEvent = createEvent.mouseLeave(mockElement);
|
||||||
fireEvent(mockElement, mouseLeaveEvent);
|
fireEvent(mockElement, mouseLeaveEvent);
|
||||||
expect(mockSizeImage).toHaveAttribute('src', mockSpoilerUri);
|
expect(mockSizeImage).to.have.attribute('src', mockSpoilerUri);
|
||||||
expect(mockSpoilerOverlay).not.toHaveClass(hiddenClass);
|
expect(mockSpoilerOverlay).not.to.have.class(hiddenClass);
|
||||||
expect(mockSpoilerOverlay).toContainHTML(mockSpoilerReason);
|
expect(mockSpoilerOverlay).to.contain.html(mockSpoilerReason);
|
||||||
};
|
};
|
||||||
let lastSpoilerType: SpoilerType;
|
let lastSpoilerType: SpoilerType;
|
||||||
|
|
||||||
|
@ -613,10 +618,10 @@ describe('Image utils', () => {
|
||||||
|
|
||||||
spoilerBlock(mockElement, mockSpoilerUri, mockSpoilerReason);
|
spoilerBlock(mockElement, mockSpoilerUri, mockSpoilerReason);
|
||||||
|
|
||||||
expect(mockImage).toHaveAttribute('src', mockSpoilerUri);
|
expect(mockImage).to.have.attribute('src', mockSpoilerUri);
|
||||||
expect(mockExplanation).toContainHTML(mockSpoilerReason);
|
expect(mockExplanation).to.contain.html(mockSpoilerReason);
|
||||||
expect(mockImageShow).toHaveClass(hiddenClass);
|
expect(mockImageShow).to.have.class(hiddenClass);
|
||||||
expect(mockImageFiltered).not.toHaveClass(hiddenClass);
|
expect(mockImageFiltered).not.to.have.class(hiddenClass);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not throw if image-filtered element is missing', () => {
|
it('should not throw if image-filtered element is missing', () => {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { fetchHtml, fetchJson, handleError } from '../requests';
|
import { fetchHtml, fetchJson, handleError } from '../requests';
|
||||||
import fetchMock from 'jest-fetch-mock';
|
import { fetchMock } from '../../../test/fetch-mock.ts';
|
||||||
|
|
||||||
describe('Request utils', () => {
|
describe('Request utils', () => {
|
||||||
const mockEndpoint = '/endpoint';
|
const mockEndpoint = '/endpoint';
|
||||||
|
|
|
@ -117,11 +117,11 @@ describe('Store utilities', () => {
|
||||||
it('should attach a storage event listener and fire when the provide key changes', () => {
|
it('should attach a storage event listener and fire when the provide key changes', () => {
|
||||||
const mockKey = `mock-watch-key-${getRandomIntBetween(1, 10)}`;
|
const mockKey = `mock-watch-key-${getRandomIntBetween(1, 10)}`;
|
||||||
const mockValue = Math.random();
|
const mockValue = Math.random();
|
||||||
const mockCallback = jest.fn();
|
const mockCallback = vi.fn();
|
||||||
setStorageValue({
|
setStorageValue({
|
||||||
[mockKey]: JSON.stringify(mockValue),
|
[mockKey]: JSON.stringify(mockValue),
|
||||||
});
|
});
|
||||||
const addEventListenerSpy = jest.spyOn(window, 'addEventListener');
|
const addEventListenerSpy = vi.spyOn(window, 'addEventListener');
|
||||||
|
|
||||||
const cleanup = store.watch(mockKey, mockCallback);
|
const cleanup = store.watch(mockKey, mockCallback);
|
||||||
|
|
||||||
|
|
3969
assets/package-lock.json
generated
3969
assets/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -3,8 +3,8 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"deploy": "cross-env NODE_ENV=production tsc && cross-env NODE_ENV=production vite build",
|
"deploy": "cross-env NODE_ENV=production tsc && cross-env NODE_ENV=production vite build",
|
||||||
"lint": "eslint . --ext .js,.ts",
|
"lint": "eslint . --ext .js,.ts",
|
||||||
"test": "jest --ci",
|
"test": "vitest run --coverage",
|
||||||
"test:watch": "jest --watch",
|
"test:watch": "vitest watch --coverage",
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "tsc && vite build",
|
"build": "tsc && vite build",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
|
@ -25,12 +25,12 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@testing-library/dom": "^10.1.0",
|
"@testing-library/dom": "^10.1.0",
|
||||||
"@testing-library/jest-dom": "^6.4.2",
|
"@types/chai-dom": "^1.11.3",
|
||||||
"@types/jest": "^29.5.12",
|
"@vitest/coverage-v8": "^1.5.3",
|
||||||
"eslint-plugin-jest": "^28.3.0",
|
"chai-dom": "^1.12.0",
|
||||||
"eslint-plugin-jest-dom": "^5.4.0",
|
"eslint-plugin-vitest": "^0.5.4",
|
||||||
"jest": "^29.7.0",
|
"jsdom": "^24.0.0",
|
||||||
"jest-fetch-mock": "^3.0.3",
|
"vitest": "^1.5.3",
|
||||||
"ts-jest": "^29.1.2"
|
"vitest-fetch-mock": "^0.2.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
4
assets/test/fetch-mock.ts
Normal file
4
assets/test/fetch-mock.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import createFetchMock from 'vitest-fetch-mock';
|
||||||
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
|
export const fetchMock = createFetchMock(vi);
|
|
@ -1,21 +0,0 @@
|
||||||
import '@testing-library/jest-dom';
|
|
||||||
import { matchNone } from '../js/query/boolean';
|
|
||||||
|
|
||||||
window.booru = {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
||||||
timeAgo: () => {},
|
|
||||||
csrfToken: 'mockCsrfToken',
|
|
||||||
hiddenTag: '/mock-tagblocked.svg',
|
|
||||||
hiddenTagList: [],
|
|
||||||
ignoredTagList: [],
|
|
||||||
imagesWithDownvotingDisabled: [],
|
|
||||||
spoilerType: 'off',
|
|
||||||
spoileredTagList: [],
|
|
||||||
userCanEditFilter: false,
|
|
||||||
userIsSignedIn: false,
|
|
||||||
watchedTagList: [],
|
|
||||||
hiddenFilter: matchNone(),
|
|
||||||
spoileredFilter: matchNone(),
|
|
||||||
interactions: [],
|
|
||||||
tagsVersion: 5
|
|
||||||
};
|
|
|
@ -1,9 +1,9 @@
|
||||||
export function mockDateNow(initialDateNow: number): void {
|
export function mockDateNow(initialDateNow: number): void {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
jest.useFakeTimers().setSystemTime(initialDateNow);
|
vi.useFakeTimers().setSystemTime(initialDateNow);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
jest.useRealTimers();
|
vi.useRealTimers();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
|
import { MockInstance } from 'vitest';
|
||||||
|
|
||||||
type MockStorageKeys = 'getItem' | 'setItem' | 'removeItem';
|
type MockStorageKeys = 'getItem' | 'setItem' | 'removeItem';
|
||||||
|
|
||||||
export function mockStorage<Keys extends MockStorageKeys>(options: Pick<Storage, Keys>): { [k in `${Keys}Spy`]: jest.SpyInstance } {
|
export function mockStorage<Keys extends MockStorageKeys>(options: Pick<Storage, Keys>): { [k in `${Keys}Spy`]: MockInstance } {
|
||||||
const getItemSpy = 'getItem' in options ? jest.spyOn(Storage.prototype, 'getItem') : undefined;
|
const getItemSpy = 'getItem' in options ? vi.spyOn(Storage.prototype, 'getItem') : undefined;
|
||||||
const setItemSpy = 'setItem' in options ? jest.spyOn(Storage.prototype, 'setItem') : undefined;
|
const setItemSpy = 'setItem' in options ? vi.spyOn(Storage.prototype, 'setItem') : undefined;
|
||||||
const removeItemSpy = 'removeItem' in options ? jest.spyOn(Storage.prototype, 'removeItem') : undefined;
|
const removeItemSpy = 'removeItem' in options ? vi.spyOn(Storage.prototype, 'removeItem') : undefined;
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
getItemSpy && getItemSpy.mockImplementation((options as Storage).getItem);
|
getItemSpy && getItemSpy.mockImplementation((options as Storage).getItem);
|
||||||
|
@ -26,7 +28,7 @@ export function mockStorage<Keys extends MockStorageKeys>(options: Pick<Storage,
|
||||||
return { getItemSpy, setItemSpy, removeItemSpy } as ReturnType<typeof mockStorage>;
|
return { getItemSpy, setItemSpy, removeItemSpy } as ReturnType<typeof mockStorage>;
|
||||||
}
|
}
|
||||||
|
|
||||||
type MockStorageImplApi = { [k in `${MockStorageKeys}Spy`]: jest.SpyInstance } & {
|
type MockStorageImplApi = { [k in `${MockStorageKeys}Spy`]: MockInstance } & {
|
||||||
/**
|
/**
|
||||||
* Forces the mock storage back to its default (empty) state
|
* Forces the mock storage back to its default (empty) state
|
||||||
* @param value
|
* @param value
|
||||||
|
|
38
assets/test/vitest-setup.ts
Normal file
38
assets/test/vitest-setup.ts
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import { matchNone } from '../js/query/boolean';
|
||||||
|
import chai from 'chai';
|
||||||
|
import chaiDom from 'chai-dom';
|
||||||
|
import { URL } from 'node:url';
|
||||||
|
import { Blob } from 'node:buffer';
|
||||||
|
import { fireEvent } from '@testing-library/dom';
|
||||||
|
|
||||||
|
chai.use(chaiDom);
|
||||||
|
|
||||||
|
window.booru = {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
|
timeAgo: () => {},
|
||||||
|
csrfToken: 'mockCsrfToken',
|
||||||
|
hiddenTag: '/mock-tagblocked.svg',
|
||||||
|
hiddenTagList: [],
|
||||||
|
ignoredTagList: [],
|
||||||
|
imagesWithDownvotingDisabled: [],
|
||||||
|
spoilerType: 'off',
|
||||||
|
spoileredTagList: [],
|
||||||
|
userCanEditFilter: false,
|
||||||
|
userIsSignedIn: false,
|
||||||
|
watchedTagList: [],
|
||||||
|
hiddenFilter: matchNone(),
|
||||||
|
spoileredFilter: matchNone(),
|
||||||
|
interactions: [],
|
||||||
|
tagsVersion: 5
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://github.com/jsdom/jsdom/issues/1721#issuecomment-1484202038
|
||||||
|
// jsdom URL and Blob are missing most of the implementation
|
||||||
|
// Use the node version of these types instead
|
||||||
|
Object.assign(globalThis, { URL, Blob });
|
||||||
|
|
||||||
|
// Prevents an error when calling `form.submit()` directly in
|
||||||
|
// the code that is being tested
|
||||||
|
HTMLFormElement.prototype.submit = function() {
|
||||||
|
fireEvent.submit(this);
|
||||||
|
};
|
|
@ -19,6 +19,8 @@
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
|
|
||||||
|
|
||||||
"strict": true
|
"strict": true,
|
||||||
|
|
||||||
|
"types": ["vitest/globals"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
|
/// <reference types="vitest" />
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import autoprefixer from 'autoprefixer';
|
import autoprefixer from 'autoprefixer';
|
||||||
import { defineConfig, UserConfig, ConfigEnv } from 'vite';
|
import { defineConfig, UserConfig, ConfigEnv } from 'vite';
|
||||||
|
|
||||||
export default defineConfig(({ command }: ConfigEnv): UserConfig => {
|
export default defineConfig(({ command, mode }: ConfigEnv): UserConfig => {
|
||||||
const isDev = command !== 'build';
|
const isDev = command !== 'build' && mode !== 'test';
|
||||||
|
|
||||||
if (isDev) {
|
if (isDev) {
|
||||||
|
// Terminate the watcher when Phoenix quits
|
||||||
|
// @see https://moroz.dev/blog/integrating-vite-js-with-phoenix-1-6
|
||||||
process.stdin.on('close', () => {
|
process.stdin.on('close', () => {
|
||||||
// eslint-disable-next-line no-process-exit
|
// eslint-disable-next-line no-process-exit
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
|
@ -61,6 +64,34 @@ export default defineConfig(({ command }: ConfigEnv): UserConfig => {
|
||||||
postcss: {
|
postcss: {
|
||||||
plugins: [autoprefixer]
|
plugins: [autoprefixer]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
globals: true,
|
||||||
|
environment: 'jsdom',
|
||||||
|
// TODO Jest --randomize CLI flag equivalent, consider enabling in the future
|
||||||
|
// sequence: { shuffle: true },
|
||||||
|
setupFiles: './test/vitest-setup.ts',
|
||||||
|
coverage: {
|
||||||
|
reporter: ['text', 'html'],
|
||||||
|
include: ['js/**/*.{js,ts}'],
|
||||||
|
exclude: [
|
||||||
|
'node_modules/',
|
||||||
|
'.*\\.test\\.ts$',
|
||||||
|
'.*\\.d\\.ts$',
|
||||||
|
],
|
||||||
|
thresholds: {
|
||||||
|
statements: 0,
|
||||||
|
branches: 0,
|
||||||
|
functions: 0,
|
||||||
|
lines: 0,
|
||||||
|
'**/utils/**/*.ts': {
|
||||||
|
statements: 100,
|
||||||
|
branches: 100,
|
||||||
|
functions: 100,
|
||||||
|
lines: 100,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue