Переглянути джерело

Unify tests

Attempt to unify tests for Jest and Cypress.
master
TheoryOfNekomata 3 роки тому
джерело
коміт
3b46b67247
16 змінених файлів з 402 додано та 487 видалено
  1. +1
    -1
      cypress.json
  2. +1
    -1
      jest.config.js
  3. +3
    -2
      package.json
  4. +0
    -90
      src/index.test.ts
  5. +6
    -78
      src/index.ts
  6. +3
    -1
      test/fixtures/templates/blank.html
  7. +23
    -0
      test/integration/blank.test.ts
  8. +42
    -0
      test/integration/everything.test.ts
  9. +114
    -0
      test/integration/single.test.ts
  10. +0
    -29
      test/integrations/blank.e2e.ts
  11. +0
    -104
      test/integrations/everything.e2e.ts
  12. +0
    -162
      test/integrations/single.e2e.ts
  13. +1
    -0
      test/support/index.ts
  14. +66
    -4
      test/utils/index.ts
  15. +0
    -12
      test/utils/search.ts
  16. +142
    -3
      yarn.lock

+ 1
- 1
cypress.json Переглянути файл

@@ -1,6 +1,6 @@
{
"fixturesFolder": "test/fixtures",
"integrationFolder": "test/integrations",
"integrationFolder": "test/integration",
"pluginsFile": "test/plugins/index.ts",
"supportFile": "test/support/index.ts"
}

+ 1
- 1
jest.config.js Переглянути файл

@@ -1,3 +1,3 @@
module.exports = {
testEnvironment: 'node',
testEnvironment: 'jsdom',
};

+ 3
- 2
package.json Переглянути файл

@@ -13,9 +13,9 @@
"scripts": {
"start": "tsdx watch",
"build": "tsdx build",
"test": "tsdx test",
"test:jsdom": "tsdx test",
"test:dom": "cypress open",
"lint": "tsdx lint",
"e2e": "cypress open",
"prepare": "tsdx build",
"size": "size-limit",
"analyze": "size-limit --why"
@@ -49,6 +49,7 @@
"@size-limit/preset-small-lib": "^4.10.2",
"@types/jsdom": "^16.2.10",
"cypress": "^7.2.0",
"cypress-jest-adapter": "^0.1.1",
"husky": "^6.0.0",
"jsdom": "^16.5.3",
"size-limit": "^4.10.2",


+ 0
- 90
src/index.test.ts Переглянути файл

@@ -1,90 +0,0 @@
import * as fixtures from '../test/utils'
import getFormValues from '.'
import {DOMWindow, JSDOM} from 'jsdom';

describe('blank template', () => {
let window: DOMWindow
beforeEach(async () => {
window = new JSDOM(await fixtures.loadTemplate('blank')).window
})
it('should have blank form value', () => {
const [form] = Array.from(window.document.getElementsByTagName('form'))
const values = getFormValues(form)
expect(values).toEqual({})
})
})

describe('single input template', () => {
let window: DOMWindow
beforeEach(async () => {
window = new JSDOM(await fixtures.loadTemplate('single-input')).window
})
it('should have a single form value', () => {
const [form] = Array.from(window.document.getElementsByTagName('form'))
const values = getFormValues(form)
expect(values).toEqual({ hello: 'Hi' })
})
})

describe('single disabled input template', () => {
let window: DOMWindow
beforeEach(async () => {
window = new JSDOM(await fixtures.loadTemplate('single-disabled-input')).window
})
it('should have blank form value', () => {
const [form] = Array.from(window.document.getElementsByTagName('form'))
const values = getFormValues(form)
expect(values).toEqual({})
})
})

describe('single readonly input template', () => {
let window: DOMWindow
beforeEach(async () => {
window = new JSDOM(await fixtures.loadTemplate('single-readonly-input')).window
})
it('should have a single form value', () => {
const [form] = Array.from(window.document.getElementsByTagName('form'))
const values = getFormValues(form)
expect(values).toEqual({ hello: 'Hi' })
})
})

describe('single input with double button submitters template', () => {
let window: DOMWindow
beforeEach(async () => {
window = new JSDOM(await fixtures.loadTemplate('single-input-with-double-button-submitters')).window
})
it('should have a single form value', () => {
const [form] = Array.from(window.document.getElementsByTagName('form'))
const values = getFormValues(form)
expect(values).toEqual({ hello: 'Hi' })
})

it('should include the submitter\'s value when provided', () => {
const [form] = Array.from(window.document.getElementsByTagName('form'))
const [submitter] = Array.from(window.document.getElementsByTagName('button'))
const values = getFormValues(form, submitter)
expect(values).toEqual({ hello: 'Hi', [submitter.name]: submitter.value })
})
})

describe('single input with double input submitters template', () => {
let window: DOMWindow
beforeEach(async () => {
window = new JSDOM(await fixtures.loadTemplate('single-input-with-double-input-submitters')).window
})

it('should have a single form value', () => {
const [form] = Array.from(window.document.getElementsByTagName('form'))
const values = getFormValues(form)
expect(values).toEqual({ hello: 'Hi' })
})

it('should include the submitter\'s value when provided', () => {
const [form] = Array.from(window.document.getElementsByTagName('form'))
const [,submitter] = Array.from(window.document.getElementsByTagName('input')).filter(i => i.type === 'submit')
const values = getFormValues(form, submitter)
expect(values).toEqual({ hello: 'Hi', [submitter.name]: submitter.value })
})
})

+ 6
- 78
src/index.ts Переглянути файл

@@ -1,26 +1,14 @@
const RadioNodeList = global.RadioNodeList || class RadioNodeList {
name: string = ''
disabled: boolean = false
}

type HTMLFieldElement
= HTMLInputElement
| HTMLButtonElement
| HTMLSelectElement
| HTMLTextAreaElement

type FieldNode
= typeof RadioNodeList
| HTMLFieldElement

type HTMLSubmitterElement
= HTMLButtonElement
| HTMLInputElement

const isFormFieldElement = (el: FieldNode) => {
if ((el as unknown) instanceof RadioNodeList) {
return true
}
const isFormFieldElement = (el: HTMLFieldElement) => {
const htmlEl = el as HTMLElement
const tagName = htmlEl.tagName
if (['SELECT', 'TEXTAREA'].includes(tagName)) {
@@ -41,71 +29,11 @@ const isFormFieldElement = (el: FieldNode) => {
return Boolean(inputEl.name)
}

const isValidFieldNode = (submitter?: HTMLSubmitterElement) => (fieldNode: Node) => {
const fieldEl = fieldNode as HTMLElement
const fieldElTagName = fieldEl.tagName

if (fieldElTagName === 'BUTTON' && Boolean(submitter as HTMLSubmitterElement)) {
const buttonEl = fieldEl as HTMLButtonElement
if (buttonEl.type === 'reset' || buttonEl.type === 'button') {
return false
}

return (
buttonEl.name === submitter!.name
&& buttonEl.value === submitter!.value
)
}

if (fieldElTagName === 'INPUT') {
const inputEl = fieldEl as HTMLInputElement
if (inputEl.type === 'radio') {
return inputEl.checked
}

if (inputEl.type === 'submit' && Boolean(submitter as HTMLSubmitterElement)) {
return (
inputEl.name === submitter!.name
&& inputEl.value === submitter!.value
)
}

if (inputEl.type === 'reset' || inputEl.type === 'button') {
return false
}
}

return true
}

const getRadioNodeListResolvedValue = (radioNodeList: RadioNodeList, submitter?: HTMLSubmitterElement) => {
const isValid = isValidFieldNode(submitter)
const validFieldElements: Node[] = Array.from(radioNodeList).filter(isValid)

if (validFieldElements.length > 1) {
return validFieldElements.map((fieldNode: Node) => (fieldNode as HTMLFieldElement).value)
}

if (validFieldElements.length > 0) {
const [validFieldElement] = (validFieldElements as HTMLFieldElement[])
if (validFieldElement) {
return validFieldElement.value
}
}

return null
}

/**
* Gets the value of a field element.
* @param el - The field element node.
* @param submitter - The element which triggered the enclosing form's submit event, if said form is submitted.
*/
const getFieldValue = (el: FieldNode, submitter?: HTMLSubmitterElement) => {
if ((el as unknown) instanceof RadioNodeList) {
return getRadioNodeListResolvedValue(el as unknown as RadioNodeList, submitter)
}

const getFieldValue = (el: HTMLFieldElement) => {
const fieldEl = el as HTMLFieldElement
const tagName = fieldEl.tagName
const type = fieldEl.type
@@ -149,7 +77,7 @@ const getFieldValue = (el: FieldNode, submitter?: HTMLSubmitterElement) => {
* Returns only named form field elements.
* @param el - The element
*/
const isValidFormField = (el: FieldNode) => {
const isValidFormField = (el: HTMLFieldElement) => {
return (
'name' in el
&& typeof el['name'] === 'string'
@@ -166,8 +94,8 @@ const getFormValues = (form: HTMLFormElement, submitter?: HTMLSubmitterElement)
if (!form) {
throw new TypeError('Invalid form element.')
}
const formElements = form.elements as unknown as Record<string | number, FieldNode>
const allFormFieldElements = Object.entries<FieldNode>(formElements)
const formElements = form.elements as unknown as Record<string | number, HTMLFieldElement>
const allFormFieldElements = Object.entries<HTMLFieldElement>(formElements)
const formFieldElements = allFormFieldElements.filter(([k, el]) => {
return (
// get only indexed forms
@@ -177,7 +105,7 @@ const getFormValues = (form: HTMLFormElement, submitter?: HTMLSubmitterElement)
})
const fieldValues = formFieldElements.reduce(
(theFormValues, [,el]) => {
const fieldValue = getFieldValue(el, submitter)
const fieldValue = getFieldValue(el)
if (fieldValue === null) {
return theFormValues
}


+ 3
- 1
test/fixtures/templates/blank.html Переглянути файл

@@ -5,6 +5,8 @@
<title>Title</title>
</head>
<body>
<form></form>
<form>
<button type="submit">Submit</button>
</form>
</body>
</html>

+ 23
- 0
test/integration/blank.test.ts Переглянути файл

@@ -0,0 +1,23 @@
/// <reference types="cypress" />
/// <reference types="cypress-jest-adapter" />

import getFormValues from '../../src'
import * as utils from '../utils'

describe('blank template', () => {
beforeEach(utils.setup('blank'))

it('should have blank form value', () => {
utils.test(
(cy: any) => {
cy.get('[type="submit"]').click()
},
(form: HTMLFormElement, search: any) => {
const before = utils.makeSearchParams(getFormValues(form)).toString();
const after = utils.makeSearchParams(search).toString();
expect(before).toEqual(after);
},
{}
);
});
})

+ 42
- 0
test/integration/everything.test.ts Переглянути файл

@@ -0,0 +1,42 @@
/// <reference types="cypress" />
/// <reference types="cypress-jest-adapter" />

import getFormValues from '../../src'
import * as utils from '../utils';

describe('blank template', () => {
beforeEach(utils.setup('everything'))

it('should have blank form value', () => {
let submitter: HTMLButtonElement
utils.test(
(cy) => {
cy.get('[name="first_name"]').type('John')
cy.get('[name="middle_name"]').type('Marcelo')
cy.get('[name="last_name"]').type('Dela Cruz')
cy.get('[name="gender"][value="m"]').check()
cy.get('[name="civil_status"]').select('Married')
cy.get('[name="new_registration"]').check()
cy.get('[name="nationality"][value="filipino"]').check()
cy.get('[name="dependent"][value="Jun"]').check()
cy.get('button.dependents').click()
cy.get('.additional-dependent [name="dependent"][type="text"]').last().type('Juana')
cy.get('button.dependents').click()
cy.get('.additional-dependent [name="dependent"][type="text"]').last().type('Jane')
cy.get('button.dependents').click()
cy.get('.additional-dependent [name="dependent"][type="text"]').last().type('Josh')
cy.get('[name="notes"]').type('Test content\n\nNew line\n\nAnother line')
cy.get('[name="submit"][value="Hi"]').then((submitterEl: any) => {
[submitter] = Array.from(submitterEl) as HTMLButtonElement[];
submitterEl.trigger('click');
})
},
(form: HTMLFormElement, search: any) => {
const before = utils.makeSearchParams(getFormValues(form, submitter)).toString();
const after = new URLSearchParams(search).toString();
expect(before).toEqual(after);
},
{}
);
});
})

+ 114
- 0
test/integration/single.test.ts Переглянути файл

@@ -0,0 +1,114 @@
/// <reference types="cypress" />

import getFormValues from '../../src'
import * as utils from '../utils';

describe('single input template', () => {
beforeEach(utils.setup('single-input'))

it('should have single form value', () => {
utils.test(
(cy: any) => {
cy.get('[type="submit"]').click()
},
(form: HTMLFormElement, search: any) => {
const before = utils.makeSearchParams(getFormValues(form)).toString();
const after = utils.makeSearchParams(search).toString();
expect(before).toEqual(after);
},
{
hello: 'Hi',
}
);
});
})

describe('single readonly template', () => {
beforeEach(utils.setup('single-readonly-input'))

it('should have single form value', () => {
utils.test(
(cy: any) => {
cy.get('[type="submit"]').click()
},
(form: HTMLFormElement, search: any) => {
const before = utils.makeSearchParams(getFormValues(form)).toString();
const after = utils.makeSearchParams(search).toString();
expect(before).toEqual(after);
},
{
hello: 'Hi',
}
);
});
})

describe('single disabled template', () => {
beforeEach(utils.setup('single-disabled-input'))

it('should have blank form value', () => {
utils.test(
(cy: any) => {
cy.get('[type="submit"]').click()
},
(form: HTMLFormElement, search: any) => {
const before = utils.makeSearchParams(getFormValues(form)).toString();
const after = utils.makeSearchParams(search).toString();
expect(before).toEqual(after);
},
{}
);
});
})

describe('single input with double button submitters template', () => {
beforeEach(utils.setup('single-input-with-double-button-submitters'))

it('should have double form values', () => {
let submitter: HTMLButtonElement
utils.test(
(cy: any) => {
cy.get('[name="action"][value="Foo"]')
.then((result: any) => {
[submitter] = Array.from(result)
})
.click()
},
(form: HTMLFormElement, search: any) => {
const before = utils.makeSearchParams(getFormValues(form, submitter)).toString();
const after = utils.makeSearchParams(search).toString();
expect(before).toEqual(after);
},
{
hello: 'Hi',
action: 'Foo',
}
);
});
})

describe('single input with double input submitters template', () => {
beforeEach(utils.setup('single-input-with-double-input-submitters'))

it('should have double form values', () => {
let submitter: HTMLInputElement
utils.test(
(cy: any) => {
cy.get('[name="action"][value="Bar"]')
.then((result: any) => {
[submitter] = Array.from(result)
})
.click()
},
(form: HTMLFormElement, search: any) => {
const before = utils.makeSearchParams(getFormValues(form, submitter)).toString();
const after = utils.makeSearchParams(search).toString();
expect(before).toEqual(after);
},
{
hello: 'Hi',
action: 'Bar',
}
);
});
})

+ 0
- 29
test/integrations/blank.e2e.ts Переглянути файл

@@ -1,29 +0,0 @@
/// <reference types="cypress" />

import getFormValues from '../../src'
import {makeSearchParams} from '../utils/search';

describe('blank template', () => {
beforeEach(() => {
cy.intercept({ url: '/' }, { fixture: 'templates/blank.html' });
cy.intercept({ url: '/?*' }, { fixture: 'templates/blank.html' }).as('submitted');
})

it('should have blank form value', () => {
let form;
cy
.visit('/')
.get('form')
.then((formResult) => {
[form] = Array.from(formResult);
})
.submit()
.wait('@submitted')
.location('search')
.then(search => {
const before = makeSearchParams(getFormValues(form)).toString();
const after = new URLSearchParams(search).toString();
expect(before).to.equal(after);
})
});
})

+ 0
- 104
test/integrations/everything.e2e.ts Переглянути файл

@@ -1,104 +0,0 @@
/// <reference types="cypress" />

import getFormValues from '../../src'
import {makeSearchParams} from '../utils/search';

describe('default template', () => {
beforeEach(() => {
cy.intercept({ url: '/' }, { fixture: 'templates/everything.html' });
cy.intercept({ url: '/?*' }, { fixture: 'templates/everything.html' }).as('submitted');
})

it('should have a single form value', () => {
let form;
let submitter;

cy
.visit('/')

cy
.get('[name="first_name"]')
.type('John')

cy
.get('[name="middle_name"]')
.type('Marcelo')

cy
.get('[name="last_name"]')
.type('Dela Cruz')

cy
.get('[name="gender"][value="m"]')
.check()

cy
.get('[name="civil_status"]')
.select('Married')

cy
.get('[name="new_registration"]')
.check()

cy
.get('[name="nationality"][value="filipino"]')
.check()

cy
.get('[name="dependent"][value="Jun"]')
.check()

cy
.get('button.dependents')
.click()

cy
.get('.additional-dependent [name="dependent"][type="text"]')
.last()
.type('Juana')

cy
.get('button.dependents')
.click()

cy
.get('.additional-dependent [name="dependent"][type="text"]')
.last()
.type('Jane')

cy
.get('button.dependents')
.click()

cy
.get('.additional-dependent [name="dependent"][type="text"]')
.last()
.type('Josh')

cy
.get('[name="notes"]')
.type('Test content\n\nNew line\n\nAnother line')

cy
.get('form')
.then((theForm) => {
[form] = Array.from(theForm)
})

cy
.get('[name="submit"][value="Hi"]')
.then((submitterEl) => {
[submitter] = Array.from(submitterEl) as HTMLButtonElement[];
submitterEl.trigger('click');
})

cy
.wait('@submitted')
.location('search')
.then(search => {
const before = makeSearchParams(getFormValues(form, submitter));
const after = new URLSearchParams(search)
expect(before.toString()).to.equal(after.toString());
})
})
});

+ 0
- 162
test/integrations/single.e2e.ts Переглянути файл

@@ -1,162 +0,0 @@
/// <reference types="cypress" />

import getFormValues from '../../src'
import {makeSearchParams} from '../utils/search';

describe('single input template', () => {
beforeEach(() => {
cy.intercept({ url: '/' }, { fixture: 'templates/single-input.html' });
cy.intercept({ url: '/?*' }, { fixture: 'templates/single-input.html' }).as('submitted');
})

it('should have a single form value', () => {
let form
cy
.visit('/')
.get('form')
.then((formResult) => {
[form] = Array.from(formResult);
})
.get('[type="submit"]')
.click()
.wait('@submitted')
.location('search')
.then(search => {
const before = makeSearchParams(getFormValues(form)).toString();
const after = new URLSearchParams(search).toString();
expect(before).to.equal(after);
})
})
});

describe('single readonly template', () => {
beforeEach(() => {
cy.intercept({ url: '/' }, { fixture: 'templates/single-readonly-input.html' });
cy.intercept({ url: '/?*' }, { fixture: 'templates/single-readonly-input.html' }).as('submitted');
})

it('should have a single form value', () => {
let form
cy
.visit('/')
.get('form')
.then((formResult) => {
[form] = Array.from(formResult);
})
.get('[type="submit"]')
.click()
.wait('@submitted')
.location('search')
.then(search => {
const before = makeSearchParams(getFormValues(form)).toString();
const after = new URLSearchParams(search).toString();
expect(before).to.equal(after);
})
})
});

describe('single disabled template', () => {
beforeEach(() => {
cy.intercept({ url: '/' }, { fixture: 'templates/single-disabled-input.html' });
cy.intercept({ url: '/?*' }, { fixture: 'templates/single-disabled-input.html' }).as('submitted');
})

it('should have a single form value', () => {
let form
cy
.visit('/')
.get('form')
.then((formResult) => {
[form] = Array.from(formResult);
})
.get('[type="submit"]')
.click()
.wait('@submitted')
.location('search')
.then(search => {
const before = makeSearchParams(getFormValues(form)).toString();
const after = new URLSearchParams(search).toString();
expect(before).to.equal(after);
})
})
});

describe('single input with double button submitters template', () => {
beforeEach(() => {
cy
.intercept(
{ url: '/' },
{ fixture: 'templates/single-input-with-double-button-submitters.html' }
);

cy
.intercept(
{ url: '/?*' },
{ fixture: 'templates/single-input-with-double-button-submitters.html' }
)
.as('submitted');
})

it('should have a single form value', () => {
let submitter;
let form;
cy
.visit('/')
.get('form')
.then((formResult) => {
[form] = Array.from(formResult);
})
.get('[name="action"][value="Bar"]')
.then((submitterEl) => {
[submitter] = Array.from(submitterEl)
})
.click()
.wait('@submitted')
.location('search')
.then(search => {
const before = makeSearchParams(getFormValues(form, submitter as HTMLInputElement)).toString();
const after = new URLSearchParams(search).toString();
expect(before).to.equal(after);
})
})
});

describe('single input with double input submitters template', () => {
beforeEach(() => {
cy
.intercept(
{ url: '/' },
{ fixture: 'templates/single-input-with-double-input-submitters.html' }
);

cy
.intercept(
{ url: '/?*' },
{ fixture: 'templates/single-input-with-double-input-submitters.html' }
)
.as('submitted');
})

it('should have a single form value', () => {
let submitter;
let form;
cy
.visit('/')
.get('form')
.then((formResult) => {
[form] = Array.from(formResult);
})
.get('[name="action"][value="Foo"]')
.then((submitterEl) => {
[submitter] = Array.from(submitterEl)
})
.click()
.wait('@submitted')
.location('search')
.then(search => {
const before = makeSearchParams(getFormValues(form, submitter as HTMLInputElement)).toString();
const after = new URLSearchParams(search).toString();
expect(before).to.equal(after);
})
})
});

+ 1
- 0
test/support/index.ts Переглянути файл

@@ -15,6 +15,7 @@

// Import commands.ts using ES2015 syntax:
import './commands'
import 'cypress-jest-adapter'

// Alternatively you can use CommonJS syntax:
// require('./commands')

+ 66
- 4
test/utils/index.ts Переглянути файл

@@ -1,8 +1,70 @@
/// <reference types="cypress" />
/// <reference types="cypress-jest-adapter" />

import fs from 'fs'
import path from 'path'

export const loadTemplate = async (templateName: string): Promise<string> => {
const templatePath = path.join('test', 'fixtures', 'templates', `${templateName}.html`)
const templateRaw = await fs.promises.readFile(templatePath)
return templateRaw.toString('utf-8')
type TestFn = (form: HTMLFormElement, after: Record<string, string> | string) => unknown

export const setup = (template: string) => {
if (typeof cy !== 'undefined') {
return () => {
cy.intercept({ url: '/' }, { fixture: `templates/${template}.html` });
cy.intercept({ url: '/?*' }, { fixture: `templates/${template}.html` }).as('submitted');
}
}
return async () => {
const templatePath = path.join('test', 'fixtures', 'templates', `${template}.html`)
const templateRaw = await fs.promises.readFile(templatePath)
window.document.open()
window.document.write(templateRaw.toString('utf-8'))
window.document.close()
}
}

export const test = (opFn: (wrapper: any) => unknown, testFn: TestFn, expectedValue: Record<string, string> | string) => {
let form: HTMLFormElement
if (typeof cy !== 'undefined') {
cy
.visit('/')
.get('form')
.then((formResult) => {
[form] = Array.from(formResult);
})

opFn(cy)

cy
.wait('@submitted')
.location('search')
.then(search => {
testFn(form, search)
})
} else {
[form] = Array.from(window.document.getElementsByTagName('form'))
testFn(form, expectedValue)
}
}

export const makeSearchParams = (beforeValues: Record<string, unknown> | string) => {
switch (typeof (beforeValues as unknown)) {
case 'string':
return new URLSearchParams(beforeValues as string)
case 'object':
return Object
.entries(beforeValues)
.reduce(
(beforeSearchParams, [key, value]) => {
const theValue = !Array.isArray(value) ? [value] : value
theValue.forEach(v => {
beforeSearchParams.append(key, v)
})
return beforeSearchParams
},
new URLSearchParams()
)
default:
break
}
throw new TypeError('Invalid parameter.')
}

+ 0
- 12
test/utils/search.ts Переглянути файл

@@ -1,12 +0,0 @@
export const makeSearchParams = (beforeValues) => Object
.entries(beforeValues)
.reduce(
(beforeSearchParams, [key, value]) => {
const theValue = !Array.isArray(value) ? [value] : value
theValue.forEach(v => {
beforeSearchParams.append(key, v)
})
return beforeSearchParams
},
new URLSearchParams()
)

+ 142
- 3
yarn.lock Переглянути файл

@@ -976,6 +976,15 @@
resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98"
integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==
"@jest/console@^24.9.0":
version "24.9.0"
resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.9.0.tgz#79b1bc06fb74a8cfb01cbdedf945584b1b9707f0"
integrity sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==
dependencies:
"@jest/source-map" "^24.9.0"
chalk "^2.0.1"
slash "^2.0.0"
"@jest/console@^25.5.0":
version "25.5.0"
resolved "https://registry.yarnpkg.com/@jest/console/-/console-25.5.0.tgz#770800799d510f37329c508a9edd0b7b447d9abb"
@@ -1082,6 +1091,15 @@
optionalDependencies:
node-notifier "^6.0.0"
"@jest/source-map@^24.9.0":
version "24.9.0"
resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-24.9.0.tgz#0e263a94430be4b41da683ccc1e6bffe2a191714"
integrity sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==
dependencies:
callsites "^3.0.0"
graceful-fs "^4.1.15"
source-map "^0.6.0"
"@jest/source-map@^25.5.0":
version "25.5.0"
resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-25.5.0.tgz#df5c20d6050aa292c2c6d3f0d2c7606af315bd1b"
@@ -1091,6 +1109,15 @@
graceful-fs "^4.2.4"
source-map "^0.6.0"
"@jest/test-result@^24.9.0":
version "24.9.0"
resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-24.9.0.tgz#11796e8aa9dbf88ea025757b3152595ad06ba0ca"
integrity sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==
dependencies:
"@jest/console" "^24.9.0"
"@jest/types" "^24.9.0"
"@types/istanbul-lib-coverage" "^2.0.0"
"@jest/test-result@^25.5.0":
version "25.5.0"
resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-25.5.0.tgz#139a043230cdeffe9ba2d8341b27f2efc77ce87c"
@@ -1134,6 +1161,15 @@
source-map "^0.6.1"
write-file-atomic "^3.0.0"
"@jest/types@^24.9.0":
version "24.9.0"
resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59"
integrity sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==
dependencies:
"@types/istanbul-lib-coverage" "^2.0.0"
"@types/istanbul-reports" "^1.1.1"
"@types/yargs" "^13.0.0"
"@jest/types@^25.5.0":
version "25.5.0"
resolved "https://registry.yarnpkg.com/@jest/types/-/types-25.5.0.tgz#4d6a4793f7b9599fc3680877b856a97dbccf2a9d"
@@ -1442,6 +1478,13 @@
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.0.tgz#dd3e6699ba3237f0348cd085e4698780204842f9"
integrity sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==
"@types/yargs@^13.0.0":
version "13.0.11"
resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-13.0.11.tgz#def2f0c93e4bdf2c61d7e34899b17e34be28d3b1"
integrity sha512-NRqD6T4gktUrDi1o1wLH3EKC1o2caCr7/wR87ODcbVITQF106OM3sFN92ysZ++wqelOd1CTzatnOBRDYYG6wGQ==
dependencies:
"@types/yargs-parser" "*"
"@types/yargs@^15.0.0":
version "15.0.13"
resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.13.tgz#34f7fec8b389d7f3c1fd08026a5763e072d3c6dc"
@@ -1755,7 +1798,7 @@ ansi-regex@^3.0.0:
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
ansi-regex@^4.1.0:
ansi-regex@^4.0.0, ansi-regex@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
@@ -2506,7 +2549,7 @@ chalk@^1.0.0, chalk@^1.1.3:
strip-ansi "^3.0.0"
supports-color "^2.0.0"
chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.1, chalk@^2.4.2:
chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1, chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@@ -3139,6 +3182,16 @@ cyclist@^1.0.1:
resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9"
integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=
cypress-jest-adapter@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/cypress-jest-adapter/-/cypress-jest-adapter-0.1.1.tgz#d1aa9d84393b6a5007022d1d33b3cdd3ce9672af"
integrity sha512-5dSB03utqDTBG5pi1LaAvYQD5uSMtSwurSzodpM+3XS/RdrjR/644oPnFUxPRvX4FVBaIY8avRs/f/GmIAiu8w==
dependencies:
expect "^24.5.0"
jest-get-type "^24.3.0"
jest-jquery-matchers "^2.1.0"
jquery "^3.4.0"
cypress@^7.2.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/cypress/-/cypress-7.2.0.tgz#6a3364e18972f898fff1fb12c1ff747939e45ddc"
@@ -3331,6 +3384,11 @@ detect-newline@^3.0.0:
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==
diff-sequences@^24.9.0:
version "24.9.0"
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5"
integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==
diff-sequences@^25.2.6:
version "25.2.6"
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd"
@@ -3940,6 +3998,18 @@ expand-brackets@^2.1.4:
snapdragon "^0.8.1"
to-regex "^3.0.1"
expect@^24.5.0:
version "24.9.0"
resolved "https://registry.yarnpkg.com/expect/-/expect-24.9.0.tgz#b75165b4817074fa4a157794f46fe9f1ba15b6ca"
integrity sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==
dependencies:
"@jest/types" "^24.9.0"
ansi-styles "^3.2.0"
jest-get-type "^24.9.0"
jest-matcher-utils "^24.9.0"
jest-message-util "^24.9.0"
jest-regex-util "^24.9.0"
expect@^25.5.0:
version "25.5.0"
resolved "https://registry.yarnpkg.com/expect/-/expect-25.5.0.tgz#f07f848712a2813bb59167da3fb828ca21f58bba"
@@ -5209,6 +5279,16 @@ jest-config@^25.5.4:
pretty-format "^25.5.0"
realpath-native "^2.0.0"
jest-diff@^24.9.0:
version "24.9.0"
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.9.0.tgz#931b7d0d5778a1baf7452cb816e325e3724055da"
integrity sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==
dependencies:
chalk "^2.0.1"
diff-sequences "^24.9.0"
jest-get-type "^24.9.0"
pretty-format "^24.9.0"
jest-diff@^25.2.1, jest-diff@^25.5.0:
version "25.5.0"
resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-25.5.0.tgz#1dd26ed64f96667c068cef026b677dfa01afcfa9"
@@ -5261,6 +5341,11 @@ jest-environment-node@^25.5.0:
jest-util "^25.5.0"
semver "^6.3.0"
jest-get-type@^24.3.0, jest-get-type@^24.9.0:
version "24.9.0"
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.9.0.tgz#1684a0c8a50f2e4901b6644ae861f579eed2ef0e"
integrity sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==
jest-get-type@^25.2.6:
version "25.2.6"
resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-25.2.6.tgz#0b0a32fab8908b44d508be81681487dbabb8d877"
@@ -5309,6 +5394,11 @@ jest-jasmine2@^25.5.4:
pretty-format "^25.5.0"
throat "^5.0.0"
jest-jquery-matchers@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/jest-jquery-matchers/-/jest-jquery-matchers-2.1.0.tgz#b56d19c460f6e57b17e6ddcce6f905d28b0ec532"
integrity sha512-gbCptZOPFv4m7CJenRJcp7OTmQ432yakCDGup6gExrIwbNq8hBfxU+llXO2IXOpFuLmI0c8A+JdGMUNXe6LV9A==
jest-leak-detector@^25.5.0:
version "25.5.0"
resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-25.5.0.tgz#2291c6294b0ce404241bb56fe60e2d0c3e34f0bb"
@@ -5317,6 +5407,16 @@ jest-leak-detector@^25.5.0:
jest-get-type "^25.2.6"
pretty-format "^25.5.0"
jest-matcher-utils@^24.9.0:
version "24.9.0"
resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz#f5b3661d5e628dffe6dd65251dfdae0e87c3a073"
integrity sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==
dependencies:
chalk "^2.0.1"
jest-diff "^24.9.0"
jest-get-type "^24.9.0"
pretty-format "^24.9.0"
jest-matcher-utils@^25.5.0:
version "25.5.0"
resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-25.5.0.tgz#fbc98a12d730e5d2453d7f1ed4a4d948e34b7867"
@@ -5327,6 +5427,20 @@ jest-matcher-utils@^25.5.0:
jest-get-type "^25.2.6"
pretty-format "^25.5.0"
jest-message-util@^24.9.0:
version "24.9.0"
resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.9.0.tgz#527f54a1e380f5e202a8d1149b0ec872f43119e3"
integrity sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==
dependencies:
"@babel/code-frame" "^7.0.0"
"@jest/test-result" "^24.9.0"
"@jest/types" "^24.9.0"
"@types/stack-utils" "^1.0.1"
chalk "^2.0.1"
micromatch "^3.1.10"
slash "^2.0.0"
stack-utils "^1.0.1"
jest-message-util@^25.5.0:
version "25.5.0"
resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-25.5.0.tgz#ea11d93204cc7ae97456e1d8716251185b8880ea"
@@ -5353,6 +5467,11 @@ jest-pnp-resolver@^1.2.1:
resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c"
integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==
jest-regex-util@^24.9.0:
version "24.9.0"
resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-24.9.0.tgz#c13fb3380bde22bf6575432c493ea8fe37965636"
integrity sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==
jest-regex-util@^25.2.1, jest-regex-util@^25.2.6:
version "25.2.6"
resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-25.2.6.tgz#d847d38ba15d2118d3b06390056028d0f2fd3964"
@@ -5545,6 +5664,11 @@ jpjs@^1.2.1:
resolved "https://registry.yarnpkg.com/jpjs/-/jpjs-1.2.1.tgz#f343833de8838a5beba1f42d5a219be0114c44b7"
integrity sha512-GxJWybWU4NV0RNKi6EIqk6IRPOTqd/h+U7sbtyuD7yUISUzV78LdHnq2xkevJsTlz/EImux4sWj+wfMiwKLkiw==
jquery@^3.4.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.6.0.tgz#c72a09f15c1bdce142f49dbf1170bdf8adac2470"
integrity sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@@ -7210,6 +7334,16 @@ pretty-bytes@^5.6.0:
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"
integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==
pretty-format@^24.9.0:
version "24.9.0"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9"
integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==
dependencies:
"@jest/types" "^24.9.0"
ansi-regex "^4.0.0"
ansi-styles "^3.2.0"
react-is "^16.8.4"
pretty-format@^25.2.1, pretty-format@^25.5.0:
version "25.5.0"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.5.0.tgz#7873c1d774f682c34b8d48b6743a2bf2ac55791a"
@@ -7374,7 +7508,7 @@ randomfill@^1.0.3:
randombytes "^2.0.5"
safe-buffer "^5.1.0"
react-is@^16.12.0, react-is@^16.8.1:
react-is@^16.12.0, react-is@^16.8.1, react-is@^16.8.4:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
@@ -8043,6 +8177,11 @@ size-limit@^4.10.2:
ora "^5.4.0"
read-pkg-up "^7.0.1"
slash@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44"
integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==
slash@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"


Завантаження…
Відмінити
Зберегти