From 8b50b1b28c66c690b47042a202d04dcee8565497 Mon Sep 17 00:00:00 2001 From: Krzysztof Jelski Date: Wed, 19 Aug 2020 11:27:52 +0200 Subject: [PATCH] A proof of concept for frontend test with substrate in docker (#3371) * React tests PoC. * Globally start and stop substrate for all tests. * Fix compilation problem. * Another attempt to make both compilation and tests work. * Apply suggestions from code review * Run slow tests with docker only nightly. * Update yarn.lock. Co-authored-by: Jaco Greeff --- .github/workflows/test-nightly.yml | 19 ++ __mocks__/fileMock.js | 6 + jest.config.js | 21 +- jest/globalSetup.ts | 28 +++ jest/globalTeardown.ts | 15 ++ jest/substrateTestsGlobal.ts | 10 + package.json | 3 +- packages/page-accounts/package.json | 4 + .../page-accounts/src/CreateAccount.spec.tsx | 63 ++++++ .../src/test-support/MemoryStore.ts | 35 +++ packages/react-components/src/Input.tsx | 1 + yarn.lock | 204 +++++++++++++++++- 12 files changed, 401 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/test-nightly.yml create mode 100644 __mocks__/fileMock.js create mode 100644 jest/globalSetup.ts create mode 100644 jest/globalTeardown.ts create mode 100644 jest/substrateTestsGlobal.ts create mode 100644 packages/page-accounts/src/CreateAccount.spec.tsx create mode 100644 packages/page-accounts/src/test-support/MemoryStore.ts diff --git a/.github/workflows/test-nightly.yml b/.github/workflows/test-nightly.yml new file mode 100644 index 0000000000..b1fdf8832b --- /dev/null +++ b/.github/workflows/test-nightly.yml @@ -0,0 +1,19 @@ +name: Nightly tests run +on: + schedule: + - cron: '1 5 * * *' + + +jobs: + alltests: + strategy: + matrix: + step: ['test:all'] + name: ${{ matrix.step }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: ${{ matrix.step }} + run: | + yarn install --immutable | grep -v 'YN0013' + yarn ${{ matrix.step }} diff --git a/__mocks__/fileMock.js b/__mocks__/fileMock.js new file mode 100644 index 0000000000..445b8204b0 --- /dev/null +++ b/__mocks__/fileMock.js @@ -0,0 +1,6 @@ +// Copyright 2019-2020 @polkadot/extension authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +// eslint-disable-line +module.exports = ''; diff --git a/jest.config.js b/jest.config.js index 342de2be88..3ba8aed0e2 100644 --- a/jest.config.js +++ b/jest.config.js @@ -14,13 +14,30 @@ const internalModules = findPackages() return modules; }, {}); -module.exports = Object.assign({}, config, { +const defaultConfig = { moduleNameMapper: { ...internalModules, '\\.(css|less)$': 'empty/object', - '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': 'empty/object' + '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': 'empty/object', + '\\.(md)$': '/__mocks__/fileMock.js' }, + testTimeout: 25000, transformIgnorePatterns: [ '/node_modules' ] +}; + +module.exports = Object.assign({}, config, { + projects: [ + { + ...defaultConfig, + displayName: 'all-tests', + globalSetup: './jest/globalSetup.ts', + globalTeardown: './jest/globalTeardown.ts' + }, + { + ...defaultConfig, + displayName: 'fast-tests' + } + ] }); diff --git a/jest/globalSetup.ts b/jest/globalSetup.ts new file mode 100644 index 0000000000..d367e9f939 --- /dev/null +++ b/jest/globalSetup.ts @@ -0,0 +1,28 @@ +// Copyright 2017-2020 @polkadot/app-accounts authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +import { GenericContainer, Wait } from 'testcontainers'; +import { SubstrateTestsGlobal } from './substrateTestsGlobal'; + +declare const global: SubstrateTestsGlobal; + +const startSubstrate = async () => { + console.log('Substrate container starting...'); + + const startedTestContainer = await new GenericContainer('parity/substrate') + .withName('polkadot-apps-test-substrate') + .withExposedPorts(9944) + .withCmd(['--dev', '--ws-port=9944', '--unsafe-ws-external']) + .withWaitStrategy(Wait.forLogMessage('New epoch 0 launching')) + .start(); + + console.log('Done.'); + + process.env.TEST_SUBSTRATE_PORT = startedTestContainer.getMappedPort(9944)?.toString() || ''; + global.__SUBSTRATE__ = startedTestContainer; +}; + +export default async (): Promise => { + await startSubstrate(); +}; diff --git a/jest/globalTeardown.ts b/jest/globalTeardown.ts new file mode 100644 index 0000000000..f2d05884a4 --- /dev/null +++ b/jest/globalTeardown.ts @@ -0,0 +1,15 @@ +// Copyright 2017-2020 @polkadot/app-accounts authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +import { SubstrateTestsGlobal } from './substrateTestsGlobal'; + +declare const global: SubstrateTestsGlobal; + +export default async (): Promise => { + console.log('Shutting down Substrate container...'); + + await global.__SUBSTRATE__.stop(); + + console.log('Done.'); +}; diff --git a/jest/substrateTestsGlobal.ts b/jest/substrateTestsGlobal.ts new file mode 100644 index 0000000000..ac74c52601 --- /dev/null +++ b/jest/substrateTestsGlobal.ts @@ -0,0 +1,10 @@ +// Copyright 2017-2020 @polkadot/app-accounts authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +import { StartedTestContainer } from 'testcontainers'; + +export interface SubstrateTestsGlobal extends NodeJS.Global { + __SUBSTRATE__: StartedTestContainer; + // You can declare anything you need. +} diff --git a/package.json b/package.json index fb39478972..3e88cc7d6d 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,8 @@ "lint:css": "stylelint './packages/**/src/**/*.tsx'", "postinstall": "polkadot-dev-yarn-only", "postinstall:electron": "electron-builder install-app-deps", - "test": "polkadot-dev-run-test packages/page-claims/src packages/apps-electron", + "test": "polkadot-dev-run-test --selectProjects=fast-tests --silent --testNamePattern='^((?!--SLOW--).)*$'", + "test:all": "polkadot-dev-run-test --selectProjects=all-tests --silent", "test:one": "polkadot-dev-run-test", "start": "yarn clean && cd packages/apps && webpack --config webpack.config.js", "start:electron": "yarn clean:electronBuild && concurrently 'yarn build:devElectronMain && cd packages/apps-electron && electron ./build/electron.js' 'yarn build:devElectronRenderer'" diff --git a/packages/page-accounts/package.json b/packages/page-accounts/package.json index 454a45056e..439f93b36a 100644 --- a/packages/page-accounts/package.json +++ b/packages/page-accounts/package.json @@ -16,5 +16,9 @@ "@polkadot/vanitygen": "^0.20.0-beta.1", "detect-browser": "^5.1.1", "file-saver": "^2.0.2" + }, + "devDependencies": { + "@testing-library/react": "^10.4.8", + "testcontainers": "^2.17.0" } } diff --git a/packages/page-accounts/src/CreateAccount.spec.tsx b/packages/page-accounts/src/CreateAccount.spec.tsx new file mode 100644 index 0000000000..4b222d9d89 --- /dev/null +++ b/packages/page-accounts/src/CreateAccount.spec.tsx @@ -0,0 +1,63 @@ +// Copyright 2017-2020 @polkadot/app-accounts authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +import AccountsApp from '@polkadot/app-accounts'; +import { MemoryStore } from '@polkadot/app-accounts/test-support/MemoryStore'; +import { Api } from '@polkadot/react-api'; +import '@polkadot/react-components/i18n'; +import { useApi } from '@polkadot/react-hooks'; +import { fireEvent, render } from '@testing-library/react'; +import React, { PropsWithChildren } from 'react'; +import { MemoryRouter } from 'react-router-dom'; + +const SUBSTRATE_PORT = Number.parseInt(process.env.TEST_SUBSTRATE_PORT || '30333'); + +const WaitForApi = ({ children }: { children: React.ReactNode }): PropsWithChildren | null => { + const api = useApi(); + + return api.isApiReady ? (children) : null; +}; + +describe('--SLOW--: Account Create', () => { + it('asks for confirmation after saving new account', async () => { + const memoryStore = new MemoryStore(); + + const { findByPlaceholderText, findByTestId, findByText } = render( + + + +
+ { /* */ + }}/> +
+
+
+
+ ); + + const addAccountButton = await findByText('Add account', {}, { timeout: 4000 }); + + fireEvent.click(addAccountButton); + + const nameInput = await findByPlaceholderText('new account'); + + fireEvent.change(nameInput, { target: { value: 'my super account' } }); + + const passwordInput = await findByTestId('password'); + + fireEvent.change(passwordInput, { target: { value: 'a' } }); + + const passwordRepeatInput = await findByTestId('password (repeat)'); + + fireEvent.change(passwordRepeatInput, { target: { value: 'a' } }); + + const saveButton = await findByText('Save'); + + fireEvent.click(saveButton); + + expect(await findByText('Create and backup account')).toBeTruthy(); + }); +}); diff --git a/packages/page-accounts/src/test-support/MemoryStore.ts b/packages/page-accounts/src/test-support/MemoryStore.ts new file mode 100644 index 0000000000..121556c975 --- /dev/null +++ b/packages/page-accounts/src/test-support/MemoryStore.ts @@ -0,0 +1,35 @@ +// Copyright 2017-2020 @polkadot/app-accounts authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +import { KeyringJson, KeyringStore } from '@polkadot/ui-keyring/types'; + +type AccountsMap = Record; + +export class MemoryStore implements KeyringStore { + private accounts: AccountsMap = {}; + + all (cb: (key: string, value: KeyringJson) => void): void { + Object.keys(this.accounts).forEach((accountsKey) => cb(accountsKey, this.accounts[accountsKey])); + } + + get (key: string, cb: (value: KeyringJson) => void): void { + cb(this.accounts[key]); + } + + remove (key: string, cb: (() => void) | undefined): void { + delete this.accounts[key]; + + if (cb) { + cb(); + } + } + + set (key: string, value: KeyringJson, cb: (() => void) | undefined): void { + this.accounts[key] = value; + + if (cb) { + cb(); + } + } +} diff --git a/packages/react-components/src/Input.tsx b/packages/react-components/src/Input.tsx index 17c0fbc240..82daec1c6a 100644 --- a/packages/react-components/src/Input.tsx +++ b/packages/react-components/src/Input.tsx @@ -198,6 +198,7 @@ function Input ({ autoFocus = false, children, className, defaultValue, help, ic : 'off' } autoCorrect='off' + data-testid={label} onPaste={_onPaste} spellCheck={false} /> diff --git a/yarn.lock b/yarn.lock index 114c5aa31b..578b6f4188 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1428,7 +1428,17 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.10.3, @babel/runtime@npm:^7.11.0, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.4": +"@babel/runtime-corejs3@npm:^7.10.2": + version: 7.11.2 + resolution: "@babel/runtime-corejs3@npm:7.11.2" + dependencies: + core-js-pure: ^3.0.0 + regenerator-runtime: ^0.13.4 + checksum: 151da4e97bb558d5a58e2a94eb89bcd505b7273c00b6ad8fe1988aefbe16aee01aa83dba0e90e56370a3e99d974d4f5fb081a6489161dc414e322d70bf19bc92 + languageName: node + linkType: hard + +"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.1, @babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.10.3, @babel/runtime@npm:^7.11.0, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.3.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.4": version: 7.11.2 resolution: "@babel/runtime@npm:7.11.2" dependencies: @@ -3099,8 +3109,10 @@ __metadata: "@babel/runtime": ^7.11.2 "@polkadot/react-components": 0.55.0-beta.4 "@polkadot/vanitygen": ^0.20.0-beta.1 + "@testing-library/react": ^10.4.8 detect-browser: ^5.1.1 file-saver: ^2.0.2 + testcontainers: ^2.17.0 languageName: unknown linkType: soft @@ -3925,6 +3937,32 @@ __metadata: languageName: node linkType: hard +"@testing-library/dom@npm:^7.17.1": + version: 7.22.2 + resolution: "@testing-library/dom@npm:7.22.2" + dependencies: + "@babel/runtime": ^7.10.3 + "@types/aria-query": ^4.2.0 + aria-query: ^4.2.2 + dom-accessibility-api: ^0.5.0 + pretty-format: ^25.5.0 + checksum: 9894fb1e1ca335099b1c3d8e5ecc2c3222bfa7ec0345c9053943d27657a554ea9c326af14a400c63cb8431de59a03baf1ec1ae4d28ec9d3abfc40db230879bc0 + languageName: node + linkType: hard + +"@testing-library/react@npm:^10.4.8": + version: 10.4.8 + resolution: "@testing-library/react@npm:10.4.8" + dependencies: + "@babel/runtime": ^7.10.3 + "@testing-library/dom": ^7.17.1 + peerDependencies: + react: "*" + react-dom: "*" + checksum: 8e725f094be47651b852a356e7fff9bcde2ab665c8ba7b0d9ef8e2140dd1158c8b58d4fcbebd4f5d03e32cff34c4c035a4d5a761903f1c908bebc2fe6abc8ec2 + languageName: node + linkType: hard + "@types/anymatch@npm:*": version: 1.3.1 resolution: "@types/anymatch@npm:1.3.1" @@ -3932,6 +3970,13 @@ __metadata: languageName: node linkType: hard +"@types/aria-query@npm:^4.2.0": + version: 4.2.0 + resolution: "@types/aria-query@npm:4.2.0" + checksum: 196c811653507cc0601bb1260ddeb58d80797306cf71638605d64d26ae324345b4b95514617942aadf5b899602623cf848ba6780e921526ef5cf0b0cae80825f + languageName: node + linkType: hard + "@types/babel__core@npm:^7.0.0, @types/babel__core@npm:^7.1.7": version: 7.1.9 resolution: "@types/babel__core@npm:7.1.9" @@ -4036,6 +4081,15 @@ __metadata: languageName: node linkType: hard +"@types/dockerode@npm:^2.5.34": + version: 2.5.34 + resolution: "@types/dockerode@npm:2.5.34" + dependencies: + "@types/node": "*" + checksum: ae3893a618b3cc43569b4face73196d82065a82b28fafc379dd75eb812097e33c8ec5151d608f3dd28cf5f60e313f3ea1b88e4f11954c46aaad371346709ad56 + languageName: node + linkType: hard + "@types/eslint-visitor-keys@npm:^1.0.0": version: 1.0.0 resolution: "@types/eslint-visitor-keys@npm:1.0.0" @@ -5709,6 +5763,16 @@ __metadata: languageName: node linkType: hard +"aria-query@npm:^4.2.2": + version: 4.2.2 + resolution: "aria-query@npm:4.2.2" + dependencies: + "@babel/runtime": ^7.10.2 + "@babel/runtime-corejs3": ^7.10.2 + checksum: dc7631b6f9aee453aee3587f1b4e998e2fca89909a7d2587d91694165d161850a8b64c433348efde78297e35473df6d79deb7abea8571f82485dad9b5401c390 + languageName: node + linkType: hard + "arr-diff@npm:^2.0.0": version: 2.0.0 resolution: "arr-diff@npm:2.0.0" @@ -5869,7 +5933,7 @@ __metadata: languageName: node linkType: hard -"asn1@npm:~0.2.3": +"asn1@npm:~0.2.0, asn1@npm:~0.2.3": version: 0.2.4 resolution: "asn1@npm:0.2.4" dependencies: @@ -6267,7 +6331,7 @@ __metadata: languageName: node linkType: hard -"bcrypt-pbkdf@npm:^1.0.0": +"bcrypt-pbkdf@npm:^1.0.0, bcrypt-pbkdf@npm:^1.0.2": version: 1.0.2 resolution: "bcrypt-pbkdf@npm:1.0.2" dependencies: @@ -8190,6 +8254,13 @@ __metadata: languageName: node linkType: hard +"core-js-pure@npm:^3.0.0": + version: 3.6.5 + resolution: "core-js-pure@npm:3.6.5" + checksum: 91fc8e0b699d5bcb11f265ad4544d08c98096b86ad6c9b4c00109616db0aa992ceb58ea82d0dbae2a16658a7aaf2922aa6f9fc1107dc3b0055270799d0414a3f + languageName: node + linkType: hard + "core-js@npm:^2.4.0, core-js@npm:^2.6.5": version: 2.6.11 resolution: "core-js@npm:2.6.11" @@ -9395,6 +9466,35 @@ __metadata: languageName: node linkType: hard +"docker-compose@npm:^0.23.5": + version: 0.23.5 + resolution: "docker-compose@npm:0.23.5" + checksum: 77085cabb40fa111cb96c1a2ce3e2ed8f3487525916d928c0ab863fb3720f636c3e0abca83b67ce4c8292b124ff7c952de1303f2aa9cc0764e0533b3c6660ed5 + languageName: node + linkType: hard + +"docker-modem@npm:^2.1.0": + version: 2.1.4 + resolution: "docker-modem@npm:2.1.4" + dependencies: + debug: ^4.1.1 + readable-stream: ^3.5.0 + split-ca: ^1.0.1 + ssh2: ^0.8.7 + checksum: 6a6a4be66ff68dff4182ba0b3b444c03786850268e6e2b3f764a3c78b9962545939cf37cfe533178d8c89156494b32ce048be911d532f4fdd4ecbec61b523ea7 + languageName: node + linkType: hard + +"dockerode@npm:^3.2.0": + version: 3.2.1 + resolution: "dockerode@npm:3.2.1" + dependencies: + docker-modem: ^2.1.0 + tar-fs: ~2.0.1 + checksum: 9b539b40002d0a32560a30378d03bb78b37429437078b1db67edf3d2258e5f3bd61cd5511b3aea1bbda0c37458b509b6db81226de81f900087fd8f1342ed57b8 + languageName: node + linkType: hard + "docsearch.js@npm:^2.5.2": version: 2.6.3 resolution: "docsearch.js@npm:2.6.3" @@ -9438,6 +9538,13 @@ __metadata: languageName: node linkType: hard +"dom-accessibility-api@npm:^0.5.0": + version: 0.5.0 + resolution: "dom-accessibility-api@npm:0.5.0" + checksum: 7dd37012f2d841e4d8898aea47ee5b36ad0d4d49182d2ddd293ae70b58b1c1b88bfab433a06e888e11ecb0200d9cd9ffedbad5ff84916e71a36ea35cffe17073 + languageName: node + linkType: hard + "dom-converter@npm:^0.2": version: 0.2.0 resolution: "dom-converter@npm:0.2.0" @@ -11577,6 +11684,13 @@ __metadata: languageName: node linkType: hard +"get-port@npm:^5.1.1": + version: 5.1.1 + resolution: "get-port@npm:5.1.1" + checksum: 75a5af5cef1e601cfa5a071d1b205ba94338f69f83f1092039bdf8e15351a76f5e6b7df7d3987bd3b7ad5d6893759d2bc28d36d8a4ee65976c3868d7efe7cf8c + languageName: node + linkType: hard + "get-stdin@npm:^4.0.1": version: 4.0.1 resolution: "get-stdin@npm:4.0.1" @@ -16829,6 +16943,13 @@ __metadata: languageName: node linkType: hard +"node-duration@npm:^1.0.4": + version: 1.0.4 + resolution: "node-duration@npm:1.0.4" + checksum: 28e395acc52d294b3970e06081047cfb7ca1226fe0ccbd8f9988e02fee0b8c057117775a318c781f9e2536ecfe1277dcb337722502f5c26d1b52b9af5e691403 + languageName: node + linkType: hard + "node-fetch-npm@npm:^2.0.2": version: 2.0.4 resolution: "node-fetch-npm@npm:2.0.4" @@ -19846,7 +19967,7 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^3.0.2, readable-stream@npm:^3.0.6, readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.6.0": +"readable-stream@npm:^3.0.2, readable-stream@npm:^3.0.6, readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.5.0, readable-stream@npm:^3.6.0": version: 3.6.0 resolution: "readable-stream@npm:3.6.0" dependencies: @@ -21588,6 +21709,13 @@ __metadata: languageName: node linkType: hard +"split-ca@npm:^1.0.1": + version: 1.0.1 + resolution: "split-ca@npm:1.0.1" + checksum: 66f620e52429cb1ba265d1c6da62b84cee724eba9b38ad1614ff72336ea69862dbc49b9f2e7689f4d1d55fdcce8d45b0d74fc78ca91297b5822b13bf01ea6497 + languageName: node + linkType: hard + "split-on-first@npm:^1.0.0": version: 1.1.0 resolution: "split-on-first@npm:1.1.0" @@ -21636,6 +21764,26 @@ __metadata: languageName: node linkType: hard +"ssh2-streams@npm:~0.4.10": + version: 0.4.10 + resolution: "ssh2-streams@npm:0.4.10" + dependencies: + asn1: ~0.2.0 + bcrypt-pbkdf: ^1.0.2 + streamsearch: ~0.1.2 + checksum: a49e4a8b8f94a7c02762a2c0653961c62b1d4968f5d9044900af57c9768fea832d348d96180ff11910eb38d62a48e7f100de5eac9a72e3215cc51e99f3d278ee + languageName: node + linkType: hard + +"ssh2@npm:^0.8.7": + version: 0.8.9 + resolution: "ssh2@npm:0.8.9" + dependencies: + ssh2-streams: ~0.4.10 + checksum: dcaf4440883b8cd18cd0b18046756f89d73eb8e4f1f93afcc41547111cbb5acbac5c6dff60df2eccb75f217e519ccddf9ac6286b0acac2b692778bab862dc07d + languageName: node + linkType: hard + "sshpk@npm:^1.7.0": version: 1.16.1 resolution: "sshpk@npm:1.16.1" @@ -21799,6 +21947,22 @@ __metadata: languageName: node linkType: hard +"stream-to-array@npm:^2.3.0": + version: 2.3.0 + resolution: "stream-to-array@npm:2.3.0" + dependencies: + any-promise: ^1.1.0 + checksum: b313d7dfa5230674ffd3442ae985d64b9f95ad7d122aa7d3fd9ebe21bf7129548afda51dda2af781e2cd31c84911253bbf549061e96a63941a45686329ccba3f + languageName: node + linkType: hard + +"streamsearch@npm:~0.1.2": + version: 0.1.2 + resolution: "streamsearch@npm:0.1.2" + checksum: f72befba95082d49be19cd4318112bc141f6cd7cbb201ee8079887f6f3cbcdf79c311977ce0eaa93d7d8c3e6b9727412f6177a87ced5b98d0fd4075723ad8eaf + languageName: node + linkType: hard + "strict-uri-encode@npm:^1.0.0": version: 1.1.0 resolution: "strict-uri-encode@npm:1.1.0" @@ -22409,7 +22573,7 @@ __metadata: languageName: node linkType: hard -"tar-fs@npm:^2.0.0": +"tar-fs@npm:^2.0.0, tar-fs@npm:^2.1.0": version: 2.1.0 resolution: "tar-fs@npm:2.1.0" dependencies: @@ -22421,6 +22585,18 @@ __metadata: languageName: node linkType: hard +"tar-fs@npm:~2.0.1": + version: 2.0.1 + resolution: "tar-fs@npm:2.0.1" + dependencies: + chownr: ^1.1.1 + mkdirp-classic: ^0.5.2 + pump: ^3.0.0 + tar-stream: ^2.0.0 + checksum: 890f546bf67836f092fc15b48324b6f29692a12ed809f36aa4855c66f2ef101a5295e196b0c9f5cf8fde5c18f44a935e7766748c29b1d9699a9d8f779b06965b + languageName: node + linkType: hard + "tar-stream@npm:^2.0.0": version: 2.1.3 resolution: "tar-stream@npm:2.1.3" @@ -22598,6 +22774,24 @@ __metadata: languageName: node linkType: hard +"testcontainers@npm:^2.17.0": + version: 2.20.0 + resolution: "testcontainers@npm:2.20.0" + dependencies: + "@types/dockerode": ^2.5.34 + byline: ^5.0.0 + debug: ^4.1.1 + docker-compose: ^0.23.5 + dockerode: ^3.2.0 + get-port: ^5.1.1 + glob: ^7.1.6 + node-duration: ^1.0.4 + stream-to-array: ^2.3.0 + tar-fs: ^2.1.0 + checksum: 389b2e2f689872ec0b82061fbea1d3af98b95587bacf9b023748902bd7e02f66aa07d65d70a0234e92bc4b1655d5be157481468ce31e30d46deb0fc3d0256c11 + languageName: node + linkType: hard + "text-extensions@npm:^1.0.0": version: 1.9.0 resolution: "text-extensions@npm:1.9.0"