diff --git a/.github/workflows/ci-pkg-common-ui.yml b/.github/workflows/ci-pkg-common-ui.yml new file mode 100644 index 000000000..585e7b62c --- /dev/null +++ b/.github/workflows/ci-pkg-common-ui.yml @@ -0,0 +1,81 @@ +# vue-skuilder/.github/workflows/ci-pkg-common-ui.yml +name: CI - Common UI Package + +on: + push: + branches: [main] + paths: + - 'packages/common-ui/**' + - 'packages/common/**' + - 'packages/db/**' + - '.github/workflows/ci-pkg-common-ui.yml' + pull_request: + branches: [main] + paths: + - 'packages/common-ui/**' + - 'packages/common/**' + - 'packages/db/**' + - '.github/workflows/ci-pkg-common-ui.yml' + +jobs: + build-and-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 18 + cache: 'yarn' + + - name: Install dependencies + run: yarn install --immutable + + # Build dependencies first + - name: Build common package + run: | + cd packages/common + yarn build + + - name: Build db package + run: | + cd packages/db + yarn build + + # Lint common-ui + - name: Lint common-ui + run: | + cd packages/common-ui + yarn lint:check + + # Build common-ui + - name: Build common-ui + run: | + cd packages/common-ui + yarn build + + # Run unit tests + - name: Run unit tests + run: | + cd packages/common-ui + yarn test:unit + + # Run component tests + - name: Run Cypress component tests + run: | + cd packages/common-ui + yarn cypress:run --component + + # Archive test artifacts if tests fail + - name: Archive Cypress screenshots and videos + uses: actions/upload-artifact@v4 + if: failure() + with: + name: cypress-artifacts + path: | + packages/common-ui/cypress/screenshots + packages/common-ui/cypress/videos + retention-days: 7 diff --git a/packages/common-ui/cypress.config.ts b/packages/common-ui/cypress.config.ts new file mode 100644 index 000000000..0f3fa39bb --- /dev/null +++ b/packages/common-ui/cypress.config.ts @@ -0,0 +1,25 @@ +// packages/common-ui/cypress.config.ts +import { defineConfig } from 'cypress'; +import { defineConfig as defineViteConfig } from 'vite'; +import vue from '@vitejs/plugin-vue'; +import { resolve } from 'path'; + +export default defineConfig({ + component: { + devServer: { + framework: 'vue', + bundler: 'vite', + viteConfig: defineViteConfig({ + plugins: [vue()], + resolve: { + alias: { + '@': './src', + }, + }, + }), + }, + specPattern: 'cypress/component/**/*.cy.{js,jsx,ts,tsx}', + supportFile: 'cypress/support/component.js', + indexHtmlFile: 'cypress/support/component-index.html', // Add this line + }, +}); diff --git a/packages/common-ui/cypress/component/StudySessionTimer.cy.ts b/packages/common-ui/cypress/component/StudySessionTimer.cy.ts new file mode 100644 index 000000000..64fa8c917 --- /dev/null +++ b/packages/common-ui/cypress/component/StudySessionTimer.cy.ts @@ -0,0 +1,98 @@ +// packages/common-ui/cypress/component/StudySessionTimer.cy.ts +import StudySessionTimer from '../../src/components/StudySessionTimer.vue'; + +describe('StudySessionTimer', () => { + it('renders correctly with default props', () => { + cy.mount(StudySessionTimer, { + props: { + timeRemaining: 180, + sessionTimeLimit: 5, + }, + }); + + // Check for the circular progress component + cy.get('[role="progressbar"]').should('exist'); + + // Check for the formatted time text (visible in tooltip) + cy.get('.v-tooltip').trigger('mouseenter'); + cy.contains('3:00 left!').should('exist'); + }); + + it('changes color when time is low', () => { + cy.mount(StudySessionTimer, { + props: { + timeRemaining: 30, // 30 seconds (below 60 seconds threshold) + sessionTimeLimit: 5, + }, + }); + + // Check for orange color class + cy.get('[role="progressbar"]') + .should('have.class', 'orange') + .or('have.class', 'orange-darken-3'); + + // Check for the time text + cy.get('.v-tooltip').trigger('mouseenter'); + cy.contains('30 seconds left!').should('exist'); + }); + + it('shows button on hover and emits add-time event when clicked', () => { + const onAddTime = cy.spy().as('onAddTime'); + + cy.mount(StudySessionTimer, { + props: { + timeRemaining: 180, + sessionTimeLimit: 5, + 'onAdd-time': onAddTime, + }, + }); + + // Button should not be visible initially + cy.get('button').should('not.be.visible'); + + // Button should appear on hover + cy.get('.timer-container').trigger('mouseenter'); + cy.get('button').should('be.visible'); + + // Click should emit event + cy.get('button').click(); + cy.get('@onAddTime').should('have.been.called'); + }); + + it('does not show button when time is zero', () => { + cy.mount(StudySessionTimer, { + props: { + timeRemaining: 0, + sessionTimeLimit: 5, + }, + }); + + // Even on hover, button should not appear + cy.get('.timer-container').trigger('mouseenter'); + cy.get('button').should('not.exist'); + }); + + it('displays correct percentage for progress indicator', () => { + cy.mount(StudySessionTimer, { + props: { + timeRemaining: 150, // 2.5 minutes + sessionTimeLimit: 5, // 5 minutes + }, + }); + + // Progress should be 50% (2.5 minutes of 5 minutes) + cy.get('[role="progressbar"]').should('have.attr', 'aria-valuenow', '50'); + }); + + it('displays correct percentage when under 60 seconds', () => { + cy.mount(StudySessionTimer, { + props: { + timeRemaining: 30, // 30 seconds + sessionTimeLimit: 5, // 5 minutes + }, + }); + + // Progress should be 50% (30 seconds of 60 seconds in the final minute) + cy.get('[role="progressbar"]').should('have.attr', 'aria-valuenow', '50'); + }); +}); diff --git a/packages/common-ui/cypress/support/component-index.d.ts b/packages/common-ui/cypress/support/component-index.d.ts new file mode 100644 index 000000000..f27a78ca8 --- /dev/null +++ b/packages/common-ui/cypress/support/component-index.d.ts @@ -0,0 +1,9 @@ +declare namespace Cypress { + interface Chainable { + /** + * Custom command to mount Vue components for testing + * @example cy.mount(Component, options) + */ + mount: typeof import('cypress/vue').mount; + } +} diff --git a/packages/common-ui/cypress/support/component-index.html b/packages/common-ui/cypress/support/component-index.html new file mode 100644 index 000000000..bf1066dee --- /dev/null +++ b/packages/common-ui/cypress/support/component-index.html @@ -0,0 +1,13 @@ + + + + + + + + Components App + + +
+ + diff --git a/packages/common-ui/cypress/support/component-styles.css b/packages/common-ui/cypress/support/component-styles.css new file mode 100644 index 000000000..746b35a14 --- /dev/null +++ b/packages/common-ui/cypress/support/component-styles.css @@ -0,0 +1,19 @@ +/* packages/common-ui/cypress/support/component-styles.css */ +body[data-cy-vuetify] { + margin: 0; + padding: 16px; + height: 100vh; +} + +#app { + padding: 24px; + height: 100%; +} + +/* Make sure Vuetify elements are visible in the test runner */ +.v-tooltip { + position: relative !important; + opacity: 1 !important; + visibility: visible !important; + transform: none !important; +} diff --git a/packages/common-ui/cypress/support/component.js b/packages/common-ui/cypress/support/component.js new file mode 100644 index 000000000..61eecd5e9 --- /dev/null +++ b/packages/common-ui/cypress/support/component.js @@ -0,0 +1,51 @@ +// packages/common-ui/cypress/support/component.js +import { mount } from 'cypress/vue'; +import { createVuetify } from 'vuetify'; +import * as components from 'vuetify/components'; +import * as directives from 'vuetify/directives'; + +// Import Vuetify styles +import 'vuetify/styles'; +import '@mdi/font/css/materialdesignicons.css'; +import './component-styles.css'; + +// Create a more complete Vuetify instance +const vuetify = createVuetify({ + components, + directives, +}); + +// Add mount command +Cypress.Commands.add('mount', (component, options = {}) => { + // Initialize options if not provided + if (!options.global) { + options.global = {}; + } + if (!options.global.plugins) { + options.global.plugins = []; + } + + // Add Vuetify to the component + options.global.plugins.push({ + install(app) { + app.use(vuetify); + }, + }); + + // Set up any global components needed + + // Set up any specific Vuetify-related configurations + const el = document.createElement('div'); + el.id = 'app'; + document.body.appendChild(el); + + // Add Vuetify CSS classes to the body + document.body.setAttribute('data-cy-vuetify', ''); + document.body.classList.add('v-application'); + document.body.classList.add('v-theme--light'); + + return mount(component, { + ...options, + attachTo: '#app', + }); +}); diff --git a/packages/common-ui/package.json b/packages/common-ui/package.json index 6ed16e3ca..c02fb7e0c 100644 --- a/packages/common-ui/package.json +++ b/packages/common-ui/package.json @@ -23,7 +23,9 @@ "build-types": "tsc --project tsconfig.types.json", "lint": "eslint . --fix", "lint:check": "eslint .", - "test:unit": "vitest run" + "test:unit": "vitest run", + "cypress:open": "cypress open --component", + "cypress:run": "cypress run --component" }, "dependencies": { "@highlightjs/vue-plugin": "^2.1.2", @@ -43,10 +45,13 @@ "vuetify": "^3.0.0" }, "devDependencies": { + "@cypress/vite-dev-server": "^6.0.3", "@typescript-eslint/eslint-plugin": "^8.25.0", "@typescript-eslint/parser": "^8.25.0", "@vitejs/plugin-vue": "^5.2.1", "@vue/eslint-config-typescript": "^14.4.0", + "cypress": "^14.2.1", + "cypress-vite": "^1.6.0", "eslint": "^9.21.0", "eslint-config-prettier": "^10.0.2", "eslint-plugin-vue": "^9.32.0", diff --git a/packages/common-ui/src/components/StudySessionTimer.vue b/packages/common-ui/src/components/StudySessionTimer.vue new file mode 100644 index 000000000..3c8352fa7 --- /dev/null +++ b/packages/common-ui/src/components/StudySessionTimer.vue @@ -0,0 +1,121 @@ + + + + + + diff --git a/packages/common-ui/src/index.ts b/packages/common-ui/src/index.ts index 9dc453d4d..ff8b78db9 100644 --- a/packages/common-ui/src/index.ts +++ b/packages/common-ui/src/index.ts @@ -21,6 +21,13 @@ export * from './components/PaginatingToolbar.types'; export * from './composables/CompositionViewable'; export * from './composables/Displayable'; +/* + Study Session Components + +*/ + +export { default as StudySessionTimer } from './components/StudySessionTimer.vue'; + /* studentInputs diff --git a/packages/common-ui/tsconfig.json b/packages/common-ui/tsconfig.json index 809a97dab..28969241f 100644 --- a/packages/common-ui/tsconfig.json +++ b/packages/common-ui/tsconfig.json @@ -16,7 +16,7 @@ "paths": { "@/*": ["src/*"] }, - "types": ["vite/client", "vitest/globals"] + "types": ["vite/client", "vitest/globals", "cypress"] }, "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.vue"], "exclude": ["node_modules", "dist"] diff --git a/packages/platform-ui/src/App.vue b/packages/platform-ui/src/App.vue index 2e38d1983..a30114ec5 100644 --- a/packages/platform-ui/src/App.vue +++ b/packages/platform-ui/src/App.vue @@ -72,7 +72,7 @@ defineOptions({ // const build = ref('0.0.2'); const latestBuild = ref(''); -const drawer = ref(false); +const drawer = ref(true); const authStore = useAuthStore(); const configStore = useConfigStore(); const theme = useTheme(); diff --git a/packages/platform-ui/src/main.ts b/packages/platform-ui/src/main.ts index 2eec4c899..abdd7c992 100644 --- a/packages/platform-ui/src/main.ts +++ b/packages/platform-ui/src/main.ts @@ -8,6 +8,7 @@ import vuetify from './plugins/vuetify'; // common-ui imports import { piniaPlugin } from '@vue-skuilder/common-ui'; import '@vue-skuilder/common-ui/style'; +// `courses` imports import '@vue-skuilder/courses/style'; const pinia = createPinia(); diff --git a/packages/platform-ui/src/views/Study.vue b/packages/platform-ui/src/views/Study.vue index de9164587..b45994999 100644 --- a/packages/platform-ui/src/views/Study.vue +++ b/packages/platform-ui/src/views/Study.vue @@ -38,11 +38,7 @@
-
-

Sign up to get to work!

-
- -
+

Study session finished! Great job!

{{ sessionController.report }}

@@ -77,63 +73,20 @@

- - - - {{ timeString }} - - - - - + + + + + + + + + +
@@ -183,7 +136,7 @@ import { } from '@vue-skuilder/common'; import confetti from 'canvas-confetti'; import moment from 'moment'; -import { alertUser } from '@vue-skuilder/common-ui'; +import { alertUser, StudySessionTimer } from '@vue-skuilder/common-ui'; import { Status, CourseConfig } from '@vue-skuilder/common'; import { useConfigStore } from '@/stores/useConfigStore'; import { useDataInputFormStore } from '@/stores/useDataInputFormStore'; @@ -210,6 +163,7 @@ export default defineComponent({ components: { CardViewer, // [ ] consider: cardloader intermediary? + StudySessionTimer, SkMouseTrap, SkTagsInput, SessionConfiguration, @@ -275,8 +229,7 @@ export default defineComponent({ sessionFinished: false, sessionRecord: [] as StudySessionRecord[], percentageRemaining: 100, - timerIsActive: false, - timeString: '', + timerIsActive: true, loading: false, userCourseRegDoc: null as CourseRegistrationDoc | null, sessionContentSources: [] as StudyContentSource[], @@ -290,15 +243,6 @@ export default defineComponent({ }, computed: { - timerColor(): string { - return this.timeRemaining > 60 ? 'primary' : 'orange darken-3'; - }, - - checkLoggedIn(): boolean { - // [ ] TODO: check if user is logged in - return true; - }, - currentCard(): StudySessionRecord { return this.sessionRecord[this.sessionRecord.length - 1]; }, @@ -417,7 +361,6 @@ export default defineComponent({ tick() { this.timeRemaining = this.sessionController!.secondsRemaining; - this.setTimeString(); this.percentageRemaining = this.timeRemaining > 60 @@ -429,19 +372,6 @@ export default defineComponent({ } }, - setTimeString() { - this.timeString = ''; - if (this.timeRemaining > 60) { - this.timeString = Math.floor(this.timeRemaining / 60).toString() + ':'; - } - const secondsRemaining: number = this.timeRemaining % 60; - this.timeString += secondsRemaining >= 10 ? secondsRemaining : '0' + secondsRemaining; - if (this.timeRemaining <= 60) { - this.timeString += ' seconds'; - } - this.timeString += ' left!'; - }, - async initStudySession(sources: ContentSourceID[], timeLimit: number) { console.log(`[Study] starting study session w/ sources: ${JSON.stringify(sources)}`); @@ -509,7 +439,7 @@ export default defineComponent({ async processResponse(this: StudyInstance, r: CardRecord) { this.$emit('emitResponse', r); - this.timerIsActive = false; + this.timerIsActive = true; r.cardID = this.cardID; r.courseID = this.courseID; @@ -756,7 +686,13 @@ export default defineComponent({ .footer-controls { position: fixed; bottom: 0; - left: 0; + background-color: var(--v-background); /* Match your app's background color */ + z-index: 100; +} + +.footer-right { + position: fixed; + bottom: 0; right: 0; background-color: var(--v-background); /* Match your app's background color */ z-index: 100; diff --git a/yarn.lock b/yarn.lock index 31ed44ea3..adcdac44d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1694,6 +1694,46 @@ __metadata: languageName: node linkType: hard +"@cypress/request@npm:^3.0.8": + version: 3.0.8 + resolution: "@cypress/request@npm:3.0.8" + dependencies: + aws-sign2: "npm:~0.7.0" + aws4: "npm:^1.8.0" + caseless: "npm:~0.12.0" + combined-stream: "npm:~1.0.6" + extend: "npm:~3.0.2" + forever-agent: "npm:~0.6.1" + form-data: "npm:~4.0.0" + http-signature: "npm:~1.4.0" + is-typedarray: "npm:~1.0.0" + isstream: "npm:~0.1.2" + json-stringify-safe: "npm:~5.0.1" + mime-types: "npm:~2.1.19" + performance-now: "npm:^2.1.0" + qs: "npm:6.14.0" + safe-buffer: "npm:^5.1.2" + tough-cookie: "npm:^5.0.0" + tunnel-agent: "npm:^0.6.0" + uuid: "npm:^8.3.2" + checksum: 10c0/76cabf6ad64df224bab9b66869f71c4fb63315f9775ef1769da9da6c8d6d470899bee7f5b800379020efb6c7f37fd16a4a8e25c61319e14cd720bd3f606a38fd + languageName: node + linkType: hard + +"@cypress/vite-dev-server@npm:^6.0.3": + version: 6.0.3 + resolution: "@cypress/vite-dev-server@npm:6.0.3" + dependencies: + debug: "npm:^4.3.4" + find-up: "npm:6.3.0" + node-html-parser: "npm:5.3.3" + semver: "npm:^7.7.1" + peerDependencies: + cypress: ">=14.0.0" + checksum: 10c0/704ebe619c98281bb7b659ab22aa4cfb6f59d8c367fa43256350449708dc47db412f6d529bae1841e4245d7a47d4d4593625112e57e7fe3b314d95d4ef1c3ce7 + languageName: node + linkType: hard + "@cypress/xvfb@npm:^1.2.4": version: 1.2.4 resolution: "@cypress/xvfb@npm:1.2.4" @@ -4950,6 +4990,7 @@ __metadata: version: 0.0.0-use.local resolution: "@vue-skuilder/common-ui@workspace:packages/common-ui" dependencies: + "@cypress/vite-dev-server": "npm:^6.0.3" "@highlightjs/vue-plugin": "npm:^2.1.2" "@mdi/font": "npm:^7.3.67" "@typescript-eslint/eslint-plugin": "npm:^8.25.0" @@ -4958,6 +4999,8 @@ __metadata: "@vue-skuilder/common": "workspace:*" "@vue-skuilder/db": "workspace:*" "@vue/eslint-config-typescript": "npm:^14.4.0" + cypress: "npm:^14.2.1" + cypress-vite: "npm:^1.6.0" eslint: "npm:^9.21.0" eslint-config-prettier: "npm:^10.0.2" eslint-plugin-vue: "npm:^9.32.0" @@ -5619,7 +5662,7 @@ __metadata: languageName: node linkType: hard -"anymatch@npm:^3.0.3": +"anymatch@npm:^3.0.3, anymatch@npm:~3.1.2": version: 3.1.3 resolution: "anymatch@npm:3.1.3" dependencies: @@ -6031,6 +6074,13 @@ __metadata: languageName: node linkType: hard +"binary-extensions@npm:^2.0.0": + version: 2.3.0 + resolution: "binary-extensions@npm:2.3.0" + checksum: 10c0/75a59cafc10fb12a11d510e77110c6c7ae3f4ca22463d52487709ca7f18f69d886aa387557cc9864fbdb10153d0bdb4caacabf11541f55e89ed6e18d12ece2b5 + languageName: node + linkType: hard + "blob-util@npm:^2.0.2": version: 2.0.2 resolution: "blob-util@npm:2.0.2" @@ -6100,7 +6150,7 @@ __metadata: languageName: node linkType: hard -"braces@npm:^3.0.3": +"braces@npm:^3.0.3, braces@npm:~3.0.2": version: 3.0.3 resolution: "braces@npm:3.0.3" dependencies: @@ -6390,6 +6440,25 @@ __metadata: languageName: node linkType: hard +"chokidar@npm:^3.5.3": + version: 3.6.0 + resolution: "chokidar@npm:3.6.0" + dependencies: + anymatch: "npm:~3.1.2" + braces: "npm:~3.0.2" + fsevents: "npm:~2.3.2" + glob-parent: "npm:~5.1.2" + is-binary-path: "npm:~2.1.0" + is-glob: "npm:~4.0.1" + normalize-path: "npm:~3.0.0" + readdirp: "npm:~3.6.0" + dependenciesMeta: + fsevents: + optional: true + checksum: 10c0/8361dcd013f2ddbe260eacb1f3cb2f2c6f2b0ad118708a343a5ed8158941a39cb8fb1d272e0f389712e74ee90ce8ba864eece9e0e62b9705cb468a2f6d917462 + languageName: node + linkType: hard + "chokidar@npm:^4.0.0, chokidar@npm:^4.0.3": version: 4.0.3 resolution: "chokidar@npm:4.0.3" @@ -6443,7 +6512,7 @@ __metadata: languageName: node linkType: hard -"cli-table3@npm:~0.6.1": +"cli-table3@npm:~0.6.1, cli-table3@npm:~0.6.5": version: 0.6.5 resolution: "cli-table3@npm:0.6.5" dependencies: @@ -6845,6 +6914,19 @@ __metadata: languageName: node linkType: hard +"css-select@npm:^4.2.1": + version: 4.3.0 + resolution: "css-select@npm:4.3.0" + dependencies: + boolbase: "npm:^1.0.0" + css-what: "npm:^6.0.1" + domhandler: "npm:^4.3.1" + domutils: "npm:^2.8.0" + nth-check: "npm:^2.0.1" + checksum: 10c0/a489d8e5628e61063d5a8fe0fa1cc7ae2478cb334a388a354e91cf2908154be97eac9fa7ed4dffe87a3e06cf6fcaa6016553115335c4fd3377e13dac7bd5a8e1 + languageName: node + linkType: hard + "css-tree@npm:^2.0.1": version: 2.3.1 resolution: "css-tree@npm:2.3.1" @@ -6855,6 +6937,13 @@ __metadata: languageName: node linkType: hard +"css-what@npm:^6.0.1": + version: 6.1.0 + resolution: "css-what@npm:6.1.0" + checksum: 10c0/a09f5a6b14ba8dcf57ae9a59474722e80f20406c53a61e9aedb0eedc693b135113ffe2983f4efc4b5065ae639442e9ae88df24941ef159c218b231011d733746 + languageName: node + linkType: hard + "css.escape@npm:^1.5.1": version: 1.5.1 resolution: "css.escape@npm:1.5.1" @@ -6888,6 +6977,18 @@ __metadata: languageName: node linkType: hard +"cypress-vite@npm:^1.6.0": + version: 1.6.0 + resolution: "cypress-vite@npm:1.6.0" + dependencies: + chokidar: "npm:^3.5.3" + debug: "npm:^4.3.4" + peerDependencies: + vite: ^2.9.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 + checksum: 10c0/0ea175b1cd5580046f76014138cc126f757789cae59c278cec029e95d704cb1cf48c46cb28e894c97bd87a252e5156a4923bbea51d71c347ff85b96668e458a4 + languageName: node + linkType: hard + "cypress@npm:*, cypress@npm:^14.1.0": version: 14.1.0 resolution: "cypress@npm:14.1.0" @@ -6941,6 +7042,59 @@ __metadata: languageName: node linkType: hard +"cypress@npm:^14.2.1": + version: 14.2.1 + resolution: "cypress@npm:14.2.1" + dependencies: + "@cypress/request": "npm:^3.0.8" + "@cypress/xvfb": "npm:^1.2.4" + "@types/sinonjs__fake-timers": "npm:8.1.1" + "@types/sizzle": "npm:^2.3.2" + arch: "npm:^2.2.0" + blob-util: "npm:^2.0.2" + bluebird: "npm:^3.7.2" + buffer: "npm:^5.7.1" + cachedir: "npm:^2.3.0" + chalk: "npm:^4.1.0" + check-more-types: "npm:^2.24.0" + ci-info: "npm:^4.1.0" + cli-cursor: "npm:^3.1.0" + cli-table3: "npm:~0.6.5" + commander: "npm:^6.2.1" + common-tags: "npm:^1.8.0" + dayjs: "npm:^1.10.4" + debug: "npm:^4.3.4" + enquirer: "npm:^2.3.6" + eventemitter2: "npm:6.4.7" + execa: "npm:4.1.0" + executable: "npm:^4.1.1" + extract-zip: "npm:2.0.1" + figures: "npm:^3.2.0" + fs-extra: "npm:^9.1.0" + getos: "npm:^3.2.1" + is-installed-globally: "npm:~0.4.0" + lazy-ass: "npm:^1.6.0" + listr2: "npm:^3.8.3" + lodash: "npm:^4.17.21" + log-symbols: "npm:^4.0.0" + minimist: "npm:^1.2.8" + ospath: "npm:^1.2.2" + pretty-bytes: "npm:^5.6.0" + process: "npm:^0.11.10" + proxy-from-env: "npm:1.0.0" + request-progress: "npm:^3.0.0" + semver: "npm:^7.7.1" + supports-color: "npm:^8.1.1" + tmp: "npm:~0.2.3" + tree-kill: "npm:1.2.2" + untildify: "npm:^4.0.0" + yauzl: "npm:^2.10.0" + bin: + cypress: bin/cypress + checksum: 10c0/d6fb64193098a9d4e55c42d81f427c42eaf1fc015179a4d17706f8c808fe672e1f400bdac90ea280dc8da7c3c80feaf58aa3b230e90877e04199e3c1394381be + languageName: node + linkType: hard + "dashdash@npm:^1.12.0": version: 1.14.1 resolution: "dashdash@npm:1.14.1" @@ -7240,6 +7394,44 @@ __metadata: languageName: node linkType: hard +"dom-serializer@npm:^1.0.1": + version: 1.4.1 + resolution: "dom-serializer@npm:1.4.1" + dependencies: + domelementtype: "npm:^2.0.1" + domhandler: "npm:^4.2.0" + entities: "npm:^2.0.0" + checksum: 10c0/67d775fa1ea3de52035c98168ddcd59418356943b5eccb80e3c8b3da53adb8e37edb2cc2f885802b7b1765bf5022aec21dfc32910d7f9e6de4c3148f095ab5e0 + languageName: node + linkType: hard + +"domelementtype@npm:^2.0.1, domelementtype@npm:^2.2.0": + version: 2.3.0 + resolution: "domelementtype@npm:2.3.0" + checksum: 10c0/686f5a9ef0fff078c1412c05db73a0dce096190036f33e400a07e2a4518e9f56b1e324f5c576a0a747ef0e75b5d985c040b0d51945ce780c0dd3c625a18cd8c9 + languageName: node + linkType: hard + +"domhandler@npm:^4.2.0, domhandler@npm:^4.3.1": + version: 4.3.1 + resolution: "domhandler@npm:4.3.1" + dependencies: + domelementtype: "npm:^2.2.0" + checksum: 10c0/5c199c7468cb052a8b5ab80b13528f0db3d794c64fc050ba793b574e158e67c93f8336e87fd81e9d5ee43b0e04aea4d8b93ed7be4899cb726a1601b3ba18538b + languageName: node + linkType: hard + +"domutils@npm:^2.8.0": + version: 2.8.0 + resolution: "domutils@npm:2.8.0" + dependencies: + dom-serializer: "npm:^1.0.1" + domelementtype: "npm:^2.2.0" + domhandler: "npm:^4.2.0" + checksum: 10c0/d58e2ae01922f0dd55894e61d18119924d88091837887bf1438f2327f32c65eb76426bd9384f81e7d6dcfb048e0f83c19b222ad7101176ad68cdc9c695b563db + languageName: node + linkType: hard + "dotenv@npm:*, dotenv@npm:^16.4.7": version: 16.4.7 resolution: "dotenv@npm:16.4.7" @@ -7412,6 +7604,13 @@ __metadata: languageName: node linkType: hard +"entities@npm:^2.0.0": + version: 2.2.0 + resolution: "entities@npm:2.2.0" + checksum: 10c0/7fba6af1f116300d2ba1c5673fc218af1961b20908638391b4e1e6d5850314ee2ac3ec22d741b3a8060479911c99305164aed19b6254bde75e7e6b1b2c3f3aa3 + languageName: node + linkType: hard + "entities@npm:^4.5.0": version: 4.5.0 resolution: "entities@npm:4.5.0" @@ -8391,6 +8590,16 @@ __metadata: languageName: node linkType: hard +"find-up@npm:6.3.0": + version: 6.3.0 + resolution: "find-up@npm:6.3.0" + dependencies: + locate-path: "npm:^7.1.0" + path-exists: "npm:^5.0.0" + checksum: 10c0/07e0314362d316b2b13f7f11ea4692d5191e718ca3f7264110127520f3347996349bf9e16805abae3e196805814bc66ef4bff2b8904dc4a6476085fc9b0eba07 + languageName: node + linkType: hard + "find-up@npm:^4.0.0, find-up@npm:^4.1.0": version: 4.1.0 resolution: "find-up@npm:4.1.0" @@ -8748,7 +8957,7 @@ __metadata: languageName: node linkType: hard -"glob-parent@npm:^5.1.2": +"glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2": version: 5.1.2 resolution: "glob-parent@npm:5.1.2" dependencies: @@ -9037,7 +9246,7 @@ __metadata: languageName: node linkType: hard -"he@npm:^1.2.0": +"he@npm:1.2.0, he@npm:^1.2.0": version: 1.2.0 resolution: "he@npm:1.2.0" bin: @@ -9401,6 +9610,15 @@ __metadata: languageName: node linkType: hard +"is-binary-path@npm:~2.1.0": + version: 2.1.0 + resolution: "is-binary-path@npm:2.1.0" + dependencies: + binary-extensions: "npm:^2.0.0" + checksum: 10c0/a16eaee59ae2b315ba36fad5c5dcaf8e49c3e27318f8ab8fa3cdb8772bf559c8d1ba750a589c2ccb096113bb64497084361a25960899cb6172a6925ab6123d38 + languageName: node + linkType: hard + "is-boolean-object@npm:^1.1.0": version: 1.1.2 resolution: "is-boolean-object@npm:1.1.2" @@ -9507,7 +9725,7 @@ __metadata: languageName: node linkType: hard -"is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3": +"is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3, is-glob@npm:~4.0.1": version: 4.0.3 resolution: "is-glob@npm:4.0.3" dependencies: @@ -10868,6 +11086,15 @@ __metadata: languageName: node linkType: hard +"locate-path@npm:^7.1.0": + version: 7.2.0 + resolution: "locate-path@npm:7.2.0" + dependencies: + p-locate: "npm:^6.0.0" + checksum: 10c0/139e8a7fe11cfbd7f20db03923cacfa5db9e14fa14887ea121345597472b4a63c1a42a8a5187defeeff6acf98fd568da7382aa39682d38f0af27433953a97751 + languageName: node + linkType: hard + "lodash.camelcase@npm:^4.3.0": version: 4.3.0 resolution: "lodash.camelcase@npm:4.3.0" @@ -11552,6 +11779,16 @@ __metadata: languageName: node linkType: hard +"node-html-parser@npm:5.3.3": + version: 5.3.3 + resolution: "node-html-parser@npm:5.3.3" + dependencies: + css-select: "npm:^4.2.1" + he: "npm:1.2.0" + checksum: 10c0/a221068f47c3e4fd29dfd8c98f1068171e1189c84cdf01653f4ffd3030eb4fe023e30c2441563b302cf816cf47a8f538bb714e13ec7b0d3a86a1838abf3e33cd + languageName: node + linkType: hard + "node-int64@npm:^0.4.0": version: 0.4.0 resolution: "node-int64@npm:0.4.0" @@ -11577,7 +11814,7 @@ __metadata: languageName: node linkType: hard -"normalize-path@npm:^3.0.0": +"normalize-path@npm:^3.0.0, normalize-path@npm:~3.0.0": version: 3.0.0 resolution: "normalize-path@npm:3.0.0" checksum: 10c0/e008c8142bcc335b5e38cf0d63cfd39d6cf2d97480af9abdbe9a439221fd4d749763bab492a8ee708ce7a194bb00c9da6d0a115018672310850489137b3da046 @@ -11600,7 +11837,7 @@ __metadata: languageName: node linkType: hard -"nth-check@npm:^2.1.1": +"nth-check@npm:^2.0.1, nth-check@npm:^2.1.1": version: 2.1.1 resolution: "nth-check@npm:2.1.1" dependencies: @@ -11789,6 +12026,15 @@ __metadata: languageName: node linkType: hard +"p-limit@npm:^4.0.0": + version: 4.0.0 + resolution: "p-limit@npm:4.0.0" + dependencies: + yocto-queue: "npm:^1.0.0" + checksum: 10c0/a56af34a77f8df2ff61ddfb29431044557fcbcb7642d5a3233143ebba805fc7306ac1d448de724352861cb99de934bc9ab74f0d16fe6a5460bdbdf938de875ad + languageName: node + linkType: hard + "p-locate@npm:^4.1.0": version: 4.1.0 resolution: "p-locate@npm:4.1.0" @@ -11807,6 +12053,15 @@ __metadata: languageName: node linkType: hard +"p-locate@npm:^6.0.0": + version: 6.0.0 + resolution: "p-locate@npm:6.0.0" + dependencies: + p-limit: "npm:^4.0.0" + checksum: 10c0/d72fa2f41adce59c198270aa4d3c832536c87a1806e0f69dffb7c1a7ca998fb053915ca833d90f166a8c082d3859eabfed95f01698a3214c20df6bb8de046312 + languageName: node + linkType: hard + "p-map@npm:^4.0.0": version: 4.0.0 resolution: "p-map@npm:4.0.0" @@ -11902,6 +12157,13 @@ __metadata: languageName: node linkType: hard +"path-exists@npm:^5.0.0": + version: 5.0.0 + resolution: "path-exists@npm:5.0.0" + checksum: 10c0/b170f3060b31604cde93eefdb7392b89d832dfbc1bed717c9718cbe0f230c1669b7e75f87e19901da2250b84d092989a0f9e44d2ef41deb09aa3ad28e691a40a + languageName: node + linkType: hard + "path-is-absolute@npm:^1.0.0": version: 1.0.1 resolution: "path-is-absolute@npm:1.0.1" @@ -11992,7 +12254,7 @@ __metadata: languageName: node linkType: hard -"picomatch@npm:^2.0.4, picomatch@npm:^2.2.2, picomatch@npm:^2.2.3, picomatch@npm:^2.3.1": +"picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.2.2, picomatch@npm:^2.2.3, picomatch@npm:^2.3.1": version: 2.3.1 resolution: "picomatch@npm:2.3.1" checksum: 10c0/26c02b8d06f03206fc2ab8d16f19960f2ff9e81a658f831ecb656d8f17d9edc799e8364b1f4a7873e89d9702dff96204be0fa26fe4181f6843f040f819dac4be @@ -12464,7 +12726,7 @@ __metadata: languageName: node linkType: hard -"qs@npm:^6.9.4": +"qs@npm:6.14.0, qs@npm:^6.9.4": version: 6.14.0 resolution: "qs@npm:6.14.0" dependencies: @@ -12573,6 +12835,15 @@ __metadata: languageName: node linkType: hard +"readdirp@npm:~3.6.0": + version: 3.6.0 + resolution: "readdirp@npm:3.6.0" + dependencies: + picomatch: "npm:^2.2.1" + checksum: 10c0/6fa848cf63d1b82ab4e985f4cf72bd55b7dcfd8e0a376905804e48c3634b7e749170940ba77b32804d5fe93b3cc521aa95a8d7e7d725f830da6d93f3669ce66b + languageName: node + linkType: hard + "redent@npm:^3.0.0": version: 3.0.0 resolution: "redent@npm:3.0.0" @@ -15848,3 +16119,10 @@ __metadata: checksum: 10c0/dceb44c28578b31641e13695d200d34ec4ab3966a5729814d5445b194933c096b7ced71494ce53a0e8820685d1d010df8b2422e5bf2cdea7e469d97ffbea306f languageName: node linkType: hard + +"yocto-queue@npm:^1.0.0": + version: 1.2.1 + resolution: "yocto-queue@npm:1.2.1" + checksum: 10c0/5762caa3d0b421f4bdb7a1926b2ae2189fc6e4a14469258f183600028eb16db3e9e0306f46e8ebf5a52ff4b81a881f22637afefbef5399d6ad440824e9b27f9f + languageName: node + linkType: hard