mirror of
https://github.com/cypress-io/cypress.git
synced 2026-01-05 14:09:46 -06:00
chore: delete ui-components package (#23950)
* chore: delete ui-components package * add dependency to frontend-shared that was previously provided by ui-components * whoops * fix deps
This commit is contained in:
@@ -1732,26 +1732,6 @@ jobs:
|
||||
path: /tmp/artifacts
|
||||
- store-npm-logs
|
||||
|
||||
ui-components-integration-tests:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- restore_cached_workspace
|
||||
- run:
|
||||
command: yarn build-for-tests
|
||||
working_directory: packages/ui-components
|
||||
- run:
|
||||
command: |
|
||||
CYPRESS_KONFIG_ENV=production \
|
||||
CYPRESS_RECORD_KEY=$MAIN_RECORD_KEY \
|
||||
yarn cypress:run --record --parallel --group ui-components
|
||||
working_directory: packages/ui-components
|
||||
- verify-mocha-results
|
||||
- store_test_results:
|
||||
path: /tmp/cypress
|
||||
- store_artifacts:
|
||||
path: /tmp/artifacts
|
||||
- store-npm-logs
|
||||
|
||||
npm-webpack-preprocessor:
|
||||
<<: *defaults
|
||||
steps:
|
||||
@@ -2502,10 +2482,6 @@ linux-x64-workflow: &linux-x64-workflow
|
||||
context: [test-runner:cypress-record-key, test-runner:percy]
|
||||
requires:
|
||||
- build
|
||||
- ui-components-integration-tests:
|
||||
context: test-runner:cypress-record-key
|
||||
requires:
|
||||
- build
|
||||
- npm-webpack-dev-server:
|
||||
requires:
|
||||
- system-tests-node-modules-install
|
||||
@@ -2577,7 +2553,6 @@ linux-x64-workflow: &linux-x64-workflow
|
||||
- server-integration-tests
|
||||
- server-unit-tests
|
||||
- test-kitchensink
|
||||
- ui-components-integration-tests
|
||||
- unit-tests
|
||||
- unit-tests-release
|
||||
- cli-visual-tests
|
||||
|
||||
@@ -14,5 +14,5 @@
|
||||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import '@packages/frontend-shared/cypress/e2e/support/e2eSupport'
|
||||
import '@packages/frontend-shared/cypress/support/e2e'
|
||||
import './commands'
|
||||
|
||||
@@ -14,5 +14,5 @@
|
||||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import '@packages/frontend-shared/cypress/e2e/support/e2eSupport'
|
||||
import '@packages/frontend-shared/cypress/support/e2e'
|
||||
import './commands'
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
"test-scripts": "mocha -r packages/ts/register --reporter spec 'scripts/unit/**/*spec.js'",
|
||||
"test-scripts-watch": "yarn test-scripts --watch --watch-extensions 'ts,js'",
|
||||
"pretest-unit": "yarn ensure-deps",
|
||||
"test-unit": "lerna exec yarn test-unit --ignore \"'{@packages/{driver,root,static,web-config,net-stubbing,rewriter,ui-components},@cypress/{webpack-dev-server,eslint-plugin-dev}}'\"",
|
||||
"test-unit": "lerna exec yarn test-unit --ignore \"'{@packages/{driver,root,static,web-config,net-stubbing,rewriter},@cypress/{webpack-dev-server,eslint-plugin-dev}}'\"",
|
||||
"pretest-watch": "yarn ensure-deps",
|
||||
"test-watch": "lerna exec yarn test-watch --ignore \"'@packages/{driver,root,static,web-config}'\"",
|
||||
"type-check": "yarn lerna exec yarn type-check --scope @tooling/system-tests && node scripts/type_check",
|
||||
@@ -90,7 +90,6 @@
|
||||
"@octokit/auth-app": "3.6.1",
|
||||
"@octokit/core": "3.6.0",
|
||||
"@percy/cli": "1.2.0",
|
||||
"@percy/cypress": "^3.1.1",
|
||||
"@semantic-release/changelog": "5.0.1",
|
||||
"@semantic-release/git": "9.0.0",
|
||||
"@types/bluebird": "3.5.29",
|
||||
|
||||
@@ -30,7 +30,7 @@ export default defineConfig({
|
||||
'just-my-luck',
|
||||
'combine-properties',
|
||||
'faker',
|
||||
'@packages/ui-components/cypress/support/customPercyCommand',
|
||||
'@packages/frontend-shared/cypress/support/customPercyCommand',
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
@@ -27,7 +27,7 @@ import { setActivePinia } from 'pinia'
|
||||
import type { Pinia } from 'pinia'
|
||||
import 'cypress-real-events/support'
|
||||
|
||||
import { installCustomPercyCommand } from '@packages/ui-components/cypress/support/customPercyCommand'
|
||||
import { installCustomPercyCommand } from '@packages/frontend-shared/cypress/support/customPercyCommand'
|
||||
|
||||
let pinia: Pinia
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import '@packages/frontend-shared/cypress/e2e/support/e2eSupport'
|
||||
import '@packages/frontend-shared/cypress/support/e2e'
|
||||
import 'cypress-real-events/support'
|
||||
import './execute-spec'
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ export default defineConfig({
|
||||
viteConfig: {
|
||||
optimizeDeps: {
|
||||
include: [
|
||||
'@packages/ui-components/cypress/support/customPercyCommand',
|
||||
'cypress/support/customPercyCommand',
|
||||
],
|
||||
},
|
||||
},
|
||||
@@ -28,6 +28,5 @@ export default defineConfig({
|
||||
},
|
||||
e2e: {
|
||||
baseUrl: 'http://localhost:5555',
|
||||
supportFile: 'cypress/e2e/support/e2eSupport.ts',
|
||||
},
|
||||
})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import path from 'path'
|
||||
import execa from 'execa'
|
||||
|
||||
import type { CyTaskResult, OpenGlobalModeOptions, RemoteGraphQLInterceptor, ResetOptionsResult, WithCtxInjected, WithCtxOptions } from './support/e2eSupport'
|
||||
import type { CyTaskResult, OpenGlobalModeOptions, RemoteGraphQLInterceptor, ResetOptionsResult, WithCtxInjected, WithCtxOptions } from '../support/e2e'
|
||||
import { fixtureDirs } from '@tooling/system-tests'
|
||||
// import type { CloudExecuteRemote } from '@packages/data-context/src/sources'
|
||||
import { makeGraphQLServer } from '@packages/graphql/src/makeGraphQLServer'
|
||||
|
||||
@@ -213,7 +213,7 @@
|
||||
"field": "scrollBehavior"
|
||||
},
|
||||
{
|
||||
"value": "cypress/e2e/support/e2eSupport.ts",
|
||||
"value": "cypress/support/e2e.ts",
|
||||
"from": "config",
|
||||
"field": "supportFile"
|
||||
},
|
||||
@@ -290,7 +290,7 @@
|
||||
"just-my-luck",
|
||||
"combine-properties",
|
||||
"faker",
|
||||
"@packages/ui-components/cypress/support/customPercyCommand"
|
||||
"cypress/support/customPercyCommand"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { registerMountFn, addVueCommand } from './common'
|
||||
import '../../src/styles/shared.scss'
|
||||
import 'virtual:windi.css'
|
||||
import 'cypress-real-events/support'
|
||||
import { installCustomPercyCommand } from '@packages/ui-components/cypress/support/customPercyCommand'
|
||||
import { installCustomPercyCommand } from './customPercyCommand'
|
||||
import { addNetworkCommands } from './onlineNetwork'
|
||||
import { GQLStubRegistry } from './mock-graphql/stubgql-Registry'
|
||||
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
import '@testing-library/cypress/add-commands'
|
||||
import { browsers } from '@packages/launcher/lib/browsers'
|
||||
import { installCustomPercyCommand } from '@packages/ui-components/cypress/support/customPercyCommand'
|
||||
import { configure } from '@testing-library/cypress'
|
||||
import i18n from '../../../src/locales/en-US.json'
|
||||
import { addNetworkCommands } from '../../support/onlineNetwork'
|
||||
import { fixtureDirs, ProjectFixtureDir } from '@tooling/system-tests'
|
||||
|
||||
import type { DataContext } from '@packages/data-context'
|
||||
import type { AuthenticatedUserShape } from '@packages/data-context/src/data'
|
||||
import type { DocumentNode, ExecutionResult } from 'graphql'
|
||||
import type { Browser, FoundBrowser, OpenModeOptions } from '@packages/types'
|
||||
import type { E2ETaskMap } from '../e2ePluginSetup'
|
||||
|
||||
import type { SinonStub } from 'sinon'
|
||||
import type sinon from 'sinon'
|
||||
import type pDefer from 'p-defer'
|
||||
import 'cypress-plugin-tab'
|
||||
import type { Response } from 'cross-fetch'
|
||||
|
||||
import type { E2ETaskMap } from '../e2e/e2ePluginSetup'
|
||||
import { installCustomPercyCommand } from './customPercyCommand'
|
||||
import i18n from '../../src/locales/en-US.json'
|
||||
import { addNetworkCommands } from './onlineNetwork'
|
||||
|
||||
configure({ testIdAttribute: 'data-cy' })
|
||||
|
||||
const NO_TIMEOUT = 1000 * 1000
|
||||
@@ -25,6 +25,7 @@
|
||||
"@iconify/json": "1.1.368",
|
||||
"@iconify/vue": "3.0.0-beta.1",
|
||||
"@intlify/vite-plugin-vue-i18n": "2.4.0",
|
||||
"@percy/core": "^1.0.0-beta.48",
|
||||
"@percy/cypress": "^3.1.0",
|
||||
"@testing-library/cypress": "8.0.0",
|
||||
"@toycode/markdown-it-class": "1.2.3",
|
||||
@@ -40,6 +41,7 @@
|
||||
"@vue/compiler-sfc": "3.2.31",
|
||||
"@vueuse/core": "7.2.2",
|
||||
"axe-core": "4.4.1",
|
||||
"browser-logos": "github:alrra/browser-logos",
|
||||
"combine-properties": "0.1.0",
|
||||
"cross-env": "6.0.3",
|
||||
"cypress-axe": "0.14.0",
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import chromeIcon from '../../../../node_modules/browser-logos/src/chrome/chrome.svg?url'
|
||||
import firefoxIcon from '../../../../node_modules/browser-logos/src/firefox/firefox.svg?url'
|
||||
import edgeIcon from '../../../../node_modules/browser-logos/src/edge/edge.svg?url'
|
||||
import electronIcon from '../../../../node_modules/browser-logos/src/electron/electron.svg?url'
|
||||
import canaryIcon from '../../../../node_modules/browser-logos/src/chrome-canary/chrome-canary.svg?url'
|
||||
import chromeBetaIcon from '../../../../node_modules/browser-logos/src/chrome-beta/chrome-beta.svg?url'
|
||||
import chromiumIcon from '../../../../node_modules/browser-logos/src/chromium/chromium.svg?url'
|
||||
import edgeBetaIcon from '../../../../node_modules/browser-logos/src/edge-beta/edge-beta.png'
|
||||
import edgeCanaryIcon from '../../../../node_modules/browser-logos/src/edge-canary/edge-canary.png'
|
||||
import edgeDevIcon from '../../../../node_modules/browser-logos/src/edge-dev/edge-dev.png'
|
||||
import firefoxNightlyIcon from '../../../../node_modules/browser-logos/src/firefox-nightly/firefox-nightly.svg?url'
|
||||
import firefoxDeveloperEditionIcon from '../../../../node_modules/browser-logos/src/firefox-developer-edition/firefox-developer-edition.svg?url'
|
||||
import webKitIcon from '../../../../node_modules/browser-logos/src/webkit/webkit.svg?url'
|
||||
import chromeIcon from 'browser-logos/src/chrome/chrome.svg?url'
|
||||
import firefoxIcon from 'browser-logos/src/firefox/firefox.svg?url'
|
||||
import edgeIcon from 'browser-logos/src/edge/edge.svg?url'
|
||||
import electronIcon from 'browser-logos/src/electron/electron.svg?url'
|
||||
import canaryIcon from 'browser-logos/src/chrome-canary/chrome-canary.svg?url'
|
||||
import chromeBetaIcon from 'browser-logos/src/chrome-beta/chrome-beta.svg?url'
|
||||
import chromiumIcon from 'browser-logos/src/chromium/chromium.svg?url'
|
||||
import edgeBetaIcon from 'browser-logos/src/edge-beta/edge-beta.png'
|
||||
import edgeCanaryIcon from 'browser-logos/src/edge-canary/edge-canary.png'
|
||||
import edgeDevIcon from 'browser-logos/src/edge-dev/edge-dev.png'
|
||||
import firefoxNightlyIcon from 'browser-logos/src/firefox-nightly/firefox-nightly.svg?url'
|
||||
import firefoxDeveloperEditionIcon from 'browser-logos/src/firefox-developer-edition/firefox-developer-edition.svg?url'
|
||||
import webKitIcon from 'browser-logos/src/webkit/webkit.svg?url'
|
||||
import genericBrowserLogo from '@packages/frontend-shared/src/assets/logos/generic-browser.svg?url'
|
||||
|
||||
export const allBrowsersIcons = {
|
||||
|
||||
@@ -24,7 +24,7 @@ export default defineConfig({
|
||||
viteConfig: {
|
||||
optimizeDeps: {
|
||||
include: [
|
||||
'@packages/ui-components/cypress/support/customPercyCommand',
|
||||
'@packages/frontend-shared/cypress/support/customPercyCommand',
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
@@ -24,7 +24,7 @@ import 'cypress-real-events/support'
|
||||
|
||||
import './commands'
|
||||
import './attachFileWithPath'
|
||||
import { installCustomPercyCommand } from '@packages/ui-components/cypress/support/customPercyCommand'
|
||||
import { installCustomPercyCommand } from '@packages/frontend-shared/cypress/support/customPercyCommand'
|
||||
|
||||
installCustomPercyCommand({
|
||||
before: () => {},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/// <reference path="../../../../frontend-shared/cypress/e2e/support/e2eSupport.ts" />
|
||||
require('../../../../frontend-shared/cypress/e2e/support/e2eSupport')
|
||||
/// <reference path="../../../../frontend-shared/cypress/support/e2e.ts" />
|
||||
require('../../../../frontend-shared/cypress/support/e2e')
|
||||
|
||||
require('./dropFileWithPath')
|
||||
require('./containsPath')
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { mount } from 'cypress/react'
|
||||
import 'cypress-real-events/support'
|
||||
import { installCustomPercyCommand } from '@packages/ui-components/cypress/support/customPercyCommand'
|
||||
import { installCustomPercyCommand } from '@packages/frontend-shared/cypress/support/customPercyCommand'
|
||||
|
||||
import '../../src/main.scss'
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'cypress-real-events/support'
|
||||
// @ts-ignore
|
||||
import { installCustomPercyCommand } from '@packages/ui-components/cypress/support/customPercyCommand'
|
||||
import { installCustomPercyCommand } from '@packages/frontend-shared/cypress/support/customPercyCommand'
|
||||
|
||||
installCustomPercyCommand({
|
||||
before () {
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
@import 'lib/tag';
|
||||
@import 'lib/tooltip';
|
||||
@import '~@reach/dialog/styles.css';
|
||||
@import '../../ui-components/src/file-opener/file-opener';
|
||||
// import all other scss files in src except if they are in lib
|
||||
// or their file name is `selector-playground` or `main`
|
||||
// NOTE: no need to import scss files in their components
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
@import 'lib/tag';
|
||||
@import 'lib/tooltip';
|
||||
@import '~@reach/dialog/styles.css';
|
||||
@import '../../ui-components/src/file-opener/file-opener';
|
||||
// import all other scss files in src except if they are in lib
|
||||
// or their file name is `selecor-playground` or `main`
|
||||
// NOTA: no need to import scss files in their components
|
||||
|
||||
@@ -9,5 +9,4 @@ $cy-tooltip-class: 'cy-tooltip';
|
||||
// NOTA: no need to import scss files in their components
|
||||
@import '../../runner/src/!(lib)*/**/!(assertions-menu|main).scss';
|
||||
|
||||
@import '../../ui-components/src/dropdown';
|
||||
@import '../../reporter/src/main-runner';
|
||||
|
||||
2
packages/ui-components/.gitignore
vendored
2
packages/ui-components/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
cypress/screenshots
|
||||
cypress/videos
|
||||
@@ -1,34 +0,0 @@
|
||||
# UI Components
|
||||
|
||||
This packages contains React components that are shared between two or more of the UI packages (`desktop-gui`, `reporter`, & `runner`).
|
||||
|
||||
## Installing
|
||||
|
||||
Dependencies can be installed with:
|
||||
|
||||
```bash
|
||||
cd packages/ui-components
|
||||
npm install
|
||||
```
|
||||
|
||||
## Developing & Testing
|
||||
|
||||
These components are best developed by using their Cypress tests.
|
||||
|
||||
Run this in one terminal tab to watch the source files
|
||||
|
||||
```bash
|
||||
npm run watch
|
||||
```
|
||||
|
||||
Run this in another terminal tab to run Cypress
|
||||
|
||||
```bash
|
||||
npm run cypress:open
|
||||
```
|
||||
|
||||
To run the tests once you can run:
|
||||
|
||||
```bash
|
||||
npm run build && npm run cypress:run
|
||||
```
|
||||
@@ -1,73 +0,0 @@
|
||||
const wp = require('@cypress/webpack-preprocessor')
|
||||
const webpackOptions = {
|
||||
mode: 'none',
|
||||
resolve: {
|
||||
extensions: ['.ts', '.js', '.jsx', '.tsx', '.png'],
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(ts|js|jsx|tsx)$/,
|
||||
exclude: /node_modules/,
|
||||
use: {
|
||||
loader: require.resolve('babel-loader'),
|
||||
options: {
|
||||
plugins: [
|
||||
[require.resolve('@babel/plugin-proposal-decorators'), { legacy: true }],
|
||||
[require.resolve('@babel/plugin-proposal-class-properties'), { loose: true }],
|
||||
],
|
||||
presets: [
|
||||
require.resolve('@babel/preset-env'),
|
||||
require.resolve('@babel/preset-react'),
|
||||
require.resolve('@babel/preset-typescript'),
|
||||
],
|
||||
babelrc: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.(eot|svg|ttf|woff|woff2)$/,
|
||||
use: [
|
||||
{
|
||||
loader: require.resolve('file-loader'),
|
||||
options: {
|
||||
name: './fonts/[name].[ext]',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(png)$/,
|
||||
use: [
|
||||
{
|
||||
loader: require.resolve('file-loader'),
|
||||
options: {
|
||||
name: './img/[name].[ext]',
|
||||
esModule: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
'fixturesFolder': false,
|
||||
'projectId': 'ypt4pf',
|
||||
'reporter': '../../node_modules/cypress-multi-reporters/index.js',
|
||||
'reporterOptions': {
|
||||
'configFile': '../../mocha-reporter-config.json',
|
||||
},
|
||||
'retries': {
|
||||
'runMode': 2,
|
||||
'openMode': 0,
|
||||
},
|
||||
'e2e': {
|
||||
setupNodeEvents (on, config) {
|
||||
on('file:preprocessor', wp({ webpackOptions }))
|
||||
|
||||
return config
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"extends": [
|
||||
"plugin:cypress/recommended",
|
||||
"plugin:@cypress/dev/react"
|
||||
]
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
import { render } from 'react-dom'
|
||||
import React from 'react'
|
||||
import { BrowserIcon } from '../../src'
|
||||
|
||||
describe('<BrowserIcon />', () => {
|
||||
const _ = Cypress._
|
||||
|
||||
const browsers = [
|
||||
'Canary',
|
||||
'Chrome',
|
||||
'Chromium',
|
||||
'Edge',
|
||||
'Edge Beta',
|
||||
'Edge Canary',
|
||||
'Edge Dev',
|
||||
'Electron',
|
||||
'Firefox',
|
||||
'Firefox Developer Edition',
|
||||
'Firefox Nightly',
|
||||
]
|
||||
|
||||
beforeEach(() => {
|
||||
cy.visit('dist/index.html')
|
||||
cy.viewport(200, 200)
|
||||
})
|
||||
|
||||
it('displays correct logo for supported browsers', () => {
|
||||
cy.render(render, <>
|
||||
{_.map(browsers, (browser) => (
|
||||
<BrowserIcon browserName={browser} key={browser} />
|
||||
))}
|
||||
</>)
|
||||
|
||||
_.each(browsers, (browser, i) => {
|
||||
cy.get('.browser-icon').eq(i)
|
||||
.should('have.attr', 'src')
|
||||
.and('include', _.kebabCase(browser))
|
||||
})
|
||||
})
|
||||
|
||||
it('displays family logo for other variants', () => {
|
||||
cy.render(render, <>
|
||||
<BrowserIcon browserName='Chrome Custom' />
|
||||
<BrowserIcon browserName='Edge Custom' />
|
||||
<BrowserIcon browserName='Electron Custom' />
|
||||
<BrowserIcon browserName='Firefox Custom' />
|
||||
<BrowserIcon browserName='Chromium Custom' />
|
||||
</>)
|
||||
|
||||
cy.get('.browser-icon').eq(0)
|
||||
.should('have.attr', 'src')
|
||||
.and('include', 'chrome')
|
||||
|
||||
cy.get('.browser-icon').eq(1)
|
||||
.should('have.attr', 'src')
|
||||
.and('include', 'edge')
|
||||
|
||||
cy.get('.browser-icon').eq(2)
|
||||
.should('have.attr', 'src')
|
||||
.and('include', 'electron')
|
||||
|
||||
cy.get('.browser-icon').eq(3)
|
||||
.should('have.attr', 'src')
|
||||
.and('include', 'firefox')
|
||||
|
||||
cy.get('.browser-icon').eq(4)
|
||||
.should('have.attr', 'src')
|
||||
.and('include', 'chromium')
|
||||
})
|
||||
|
||||
it('displays generic logo for unsupported browsers', () => {
|
||||
cy.render(render, <BrowserIcon browserName='custom' />)
|
||||
cy.get('.browser-icon').should('have.class', 'fa-globe')
|
||||
})
|
||||
})
|
||||
@@ -1,92 +0,0 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-dom'
|
||||
import { Dropdown } from '../../'
|
||||
|
||||
describe('<Dropdown />', () => {
|
||||
let defaultProps
|
||||
|
||||
beforeEach(() => {
|
||||
defaultProps = {
|
||||
chosen: { name: 'First' },
|
||||
others: [{ name: 'Second' }, { name: 'Third' }],
|
||||
keyProperty: 'name',
|
||||
renderItem: ({ name }) => name,
|
||||
onSelect: () => {},
|
||||
}
|
||||
|
||||
cy.visit('dist/index.html')
|
||||
|
||||
cy.viewport(400, 600)
|
||||
})
|
||||
|
||||
it('displays chosen option and hides others', () => {
|
||||
cy.render(render, <Dropdown {...defaultProps} />)
|
||||
|
||||
cy.contains('First').should('be.visible')
|
||||
cy.contains('Second').should('not.be.visible')
|
||||
cy.contains('Third').should('not.be.visible')
|
||||
})
|
||||
|
||||
it('shows others after clicking chosen option', () => {
|
||||
cy.render(render, <Dropdown {...defaultProps} />)
|
||||
|
||||
cy.contains('First').click()
|
||||
cy.contains('Second').should('be.visible')
|
||||
cy.contains('Third').should('be.visible')
|
||||
})
|
||||
|
||||
it('calls onSelect after clicking option', () => {
|
||||
const onSelect = cy.stub()
|
||||
|
||||
cy.render(render, <Dropdown {...defaultProps} onSelect={onSelect} />)
|
||||
|
||||
cy.contains('First').click()
|
||||
cy.contains('Second').click().then(() => {
|
||||
expect(onSelect).to.be.calledWith({ name: 'Second' })
|
||||
})
|
||||
})
|
||||
|
||||
it('applies className to container', () => {
|
||||
cy.render(render, <Dropdown {...defaultProps} className="custom-class" />)
|
||||
|
||||
cy.get('.dropdown').should('have.class', 'custom-class')
|
||||
})
|
||||
|
||||
it('renders item as specified by renderItem prop', () => {
|
||||
cy.render(render, <Dropdown {...defaultProps} renderItem={({ name }) => <span>{name}</span>} />)
|
||||
|
||||
cy.contains('First').children().should('match', 'span')
|
||||
cy.contains('Second').should('match', 'span')
|
||||
cy.contains('Third').should('match', 'span')
|
||||
})
|
||||
|
||||
it('renders caret if there are items', () => {
|
||||
cy.render(render, <Dropdown {...defaultProps} />)
|
||||
|
||||
cy.get('.dropdown-caret')
|
||||
})
|
||||
|
||||
it('does not render caret if there are no items', () => {
|
||||
cy.render(render, <Dropdown {...defaultProps} others={[]}/>)
|
||||
|
||||
cy.get('.dropdown-caret').should('not.exist')
|
||||
})
|
||||
|
||||
it('disables if disabled specified and does not render options or caret', () => {
|
||||
cy.render(render, <Dropdown {...defaultProps} disabled/>)
|
||||
|
||||
cy.contains('First').should('have.class', 'disabled').click({ force: true })
|
||||
cy.get('.dropdown li').should('not.exist')
|
||||
cy.get('.dropdown-caret').should('not.exist')
|
||||
})
|
||||
|
||||
it('closes dropdown when clicking outside of it', () => {
|
||||
cy.document().then((doc) => {
|
||||
cy.render(render, <Dropdown {...defaultProps} document={doc} />)
|
||||
})
|
||||
|
||||
cy.contains('First').click()
|
||||
cy.get('body').click()
|
||||
cy.contains('Second').should('not.be.visible')
|
||||
})
|
||||
})
|
||||
@@ -1,157 +0,0 @@
|
||||
import chaiSubset from 'chai-subset'
|
||||
import { action } from 'mobx'
|
||||
import { observer, useLocalStore } from 'mobx-react'
|
||||
import { render } from 'react-dom'
|
||||
import React from 'react'
|
||||
|
||||
import { EditorPicker } from '../../'
|
||||
|
||||
chai.use(chaiSubset)
|
||||
|
||||
const _ = Cypress._
|
||||
|
||||
describe('<EditorPicker />', () => {
|
||||
let defaultProps
|
||||
|
||||
beforeEach(() => {
|
||||
defaultProps = {
|
||||
chosen: { id: 'vscode', name: 'VS Code', binary: 'vscode', isOther: false },
|
||||
editors: [
|
||||
{ id: 'computer', name: 'On Computer', binary: 'computer', isOther: false, description: 'Opens on computer etc etc' },
|
||||
{ id: 'atom', name: 'Atom', binary: 'atom', isOther: false },
|
||||
{ id: 'sublime', name: 'Sublime Text', binary: 'sublime', isOther: false },
|
||||
{ id: 'vscode', name: 'VS Code', binary: 'vscode', isOther: false },
|
||||
{ id: 'other', name: 'Other', binary: '', isOther: true, description: 'Enter the full path etc etc' },
|
||||
],
|
||||
onSelect: () => {},
|
||||
}
|
||||
|
||||
cy.visit('dist/index.html')
|
||||
cy.viewport(400, 600)
|
||||
})
|
||||
|
||||
it('renders each specified editor', () => {
|
||||
cy.render(render, <EditorPicker {...defaultProps} />)
|
||||
|
||||
cy.contains('On Computer')
|
||||
cy.contains('Atom')
|
||||
cy.contains('Sublime Text')
|
||||
cy.contains('VS Code')
|
||||
cy.contains('Other')
|
||||
})
|
||||
|
||||
it('has chosen editor selected', () => {
|
||||
cy.render(render, <EditorPicker {...defaultProps} />)
|
||||
|
||||
cy.contains('VS Code').find('input').should('be.checked')
|
||||
})
|
||||
|
||||
it('has none chosen if not specified', () => {
|
||||
cy.render(render, <EditorPicker {...defaultProps} chosen={undefined} />)
|
||||
|
||||
cy.get('input[type="radio"]').should('not.be.checked')
|
||||
})
|
||||
|
||||
// NOTE: this doesn't work currently because the tooltip renders in the spec
|
||||
// iframe and not the AUT iframe. need to switch to @cypress/react
|
||||
// or something similar to get this to work
|
||||
it.skip('shows info circle with desciption tooltip when specified', () => {
|
||||
cy.render(render, <EditorPicker {...defaultProps} />)
|
||||
|
||||
cy.get('.fa-info-circle').trigger('mouseover')
|
||||
cy.get('.cy-tooltip')
|
||||
.should('be.visible')
|
||||
.should('have.text', 'Opens on computer etc etc')
|
||||
})
|
||||
|
||||
it('calls onSelect when option is chosen', () => {
|
||||
const onSelect = cy.stub()
|
||||
|
||||
cy.render(render, <EditorPicker {...defaultProps} onSelect={onSelect}/>)
|
||||
|
||||
cy.contains('Sublime Text').click().then(() => {
|
||||
expect(onSelect).to.be.calledWith(defaultProps.editors[2])
|
||||
})
|
||||
})
|
||||
|
||||
describe('"Other" handling', () => {
|
||||
it('shows description when chosen', () => {
|
||||
cy.render(render, <EditorPicker {...defaultProps} chosen={defaultProps.editors[4]}/>)
|
||||
|
||||
cy.contains('Enter the full path').should('be.visible')
|
||||
})
|
||||
|
||||
it('selects item when focusing text input', () => {
|
||||
cy.render(render, <EditorPicker {...defaultProps} chosen={defaultProps.editors[4]}/>)
|
||||
|
||||
cy.contains('Other').find('input[type="text"]').focus()
|
||||
cy.contains('Other').find('input[type="radio"]').should('be.checked')
|
||||
})
|
||||
|
||||
it('populates path if specified', () => {
|
||||
defaultProps.editors[4].binary = '/path/to/my/editor'
|
||||
cy.render(render, <EditorPicker {...defaultProps} chosen={defaultProps.editors[4]}/>)
|
||||
|
||||
cy.contains('Other').find('input[type="text"]').should('have.value', '/path/to/my/editor')
|
||||
})
|
||||
|
||||
describe('typing path', () => {
|
||||
const path = '/path/to/my/editor'
|
||||
const Wrapper = observer(({ onSelectSpy }) => {
|
||||
const state = useLocalStore(() => ({
|
||||
editors: defaultProps.editors,
|
||||
setChosenEditor: action((editor) => {
|
||||
state.chosenEditor = editor
|
||||
}),
|
||||
setOtherPath: action((otherPath) => {
|
||||
const otherOption = _.find(state.editors, { isOther: true })
|
||||
|
||||
otherOption.binary = otherPath
|
||||
}),
|
||||
}))
|
||||
|
||||
const onSelect = (chosen) => {
|
||||
state.setChosenEditor(chosen)
|
||||
onSelectSpy(chosen)
|
||||
}
|
||||
|
||||
return (
|
||||
<EditorPicker
|
||||
{...defaultProps}
|
||||
editors={state.editors}
|
||||
chosen={state.chosen}
|
||||
onSelect={onSelect}
|
||||
onUpdateOtherPath={state.setOtherPath}
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
||||
it('trims the path', () => {
|
||||
const onSelect = cy.stub()
|
||||
|
||||
cy.render(render, <Wrapper onSelectSpy={onSelect} />)
|
||||
|
||||
cy.contains('Other').find('input[type="text"]').type(` ${path} `, { delay: 0 })
|
||||
.should(() => {
|
||||
expect(onSelect.lastCall.args[0].binary).to.equal(path)
|
||||
})
|
||||
})
|
||||
|
||||
it('calls onSelect for every character typed', () => {
|
||||
const onSelect = cy.stub()
|
||||
|
||||
cy.render(render, <Wrapper onSelectSpy={onSelect} />)
|
||||
|
||||
_.each(path.split(''), (letter, i) => {
|
||||
const pathSoFar = path.substring(0, i + 1)
|
||||
|
||||
cy.contains('Other').find('input[type="text"]').type(letter, { delay: 0 })
|
||||
.should(() => {
|
||||
expect(onSelect.lastCall.args[0].id).to.equal('other')
|
||||
expect(onSelect.lastCall.args[0].binary).to.equal(pathSoFar)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,179 +0,0 @@
|
||||
import React from 'react'
|
||||
import { render } from 'react-dom'
|
||||
|
||||
import { FileOpener } from '../../'
|
||||
|
||||
const _ = Cypress._
|
||||
|
||||
const fileDetails = {
|
||||
absoluteFile: '/absolute/path/to/file_spec.js',
|
||||
column: 0,
|
||||
line: 0,
|
||||
originalFile: 'path/to/file_spec.js',
|
||||
relativeFile: 'path/to/file_spec.js',
|
||||
}
|
||||
|
||||
const preferredOpener = {
|
||||
id: 'vscode',
|
||||
name: 'VS Code',
|
||||
binary: 'vscode',
|
||||
isOther: false,
|
||||
}
|
||||
|
||||
const availableEditors = [
|
||||
{ id: 'computer', name: 'On Computer', binary: 'computer', isOther: false, description: 'Opens on computer etc etc' },
|
||||
{ id: 'atom', name: 'Atom', binary: 'atom', isOther: false },
|
||||
{ id: 'sublime', name: 'Sublime Text', binary: 'sublime', isOther: false },
|
||||
{ id: 'vscode', name: 'VS Code', binary: 'vscode', isOther: false },
|
||||
{ id: 'other', name: 'Other', binary: '', isOther: true, description: 'Enter the full path etc etc' },
|
||||
]
|
||||
|
||||
describe('<FileOpener />', () => {
|
||||
let defaultProps
|
||||
|
||||
beforeEach(() => {
|
||||
defaultProps = {
|
||||
fileDetails,
|
||||
openFile: () => {},
|
||||
getUserEditor: (callback) => {
|
||||
callback({
|
||||
preferredOpener,
|
||||
availableEditors,
|
||||
})
|
||||
},
|
||||
setUserEditor: () => {},
|
||||
className: 'file-opener',
|
||||
}
|
||||
|
||||
cy.visit('dist/index.html')
|
||||
cy.viewport(600, 600)
|
||||
})
|
||||
|
||||
it('renders link text', () => {
|
||||
cy.render(render, <FileOpener {...defaultProps}>Open in IDE</FileOpener>)
|
||||
|
||||
cy.get('.file-opener').should('have.text', 'Open in IDE')
|
||||
})
|
||||
|
||||
context('when user has already set opener and opens file', () => {
|
||||
it('opens in preferred opener', () => {
|
||||
const openFile = cy.stub()
|
||||
|
||||
cy.render(render, <FileOpener {...defaultProps} openFile={openFile}>Open in IDE</FileOpener>)
|
||||
|
||||
cy.get('.file-opener').click().then(() => {
|
||||
expect(openFile).to.be.calledWith(preferredOpener, fileDetails)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('when user has not already set opener and opens file', () => {
|
||||
let defaultPropsModal
|
||||
|
||||
beforeEach(() => {
|
||||
defaultPropsModal = {
|
||||
...defaultProps,
|
||||
getUserEditor: (callback) => {
|
||||
callback({
|
||||
availableEditors,
|
||||
})
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
it('opens modal with available editors', () => {
|
||||
cy.render(render, <FileOpener {...defaultPropsModal}>Open in IDE</FileOpener>)
|
||||
|
||||
cy.get('.file-opener').click()
|
||||
|
||||
_.each(availableEditors, ({ name }) => {
|
||||
cy.contains(name)
|
||||
})
|
||||
|
||||
cy.contains('Set preference and open file')
|
||||
})
|
||||
|
||||
it('closes modal when cancel is clicked', () => {
|
||||
cy.render(render, <FileOpener {...defaultPropsModal}>Open in IDE</FileOpener>)
|
||||
|
||||
cy.get('.file-opener').click()
|
||||
cy.contains('Sublime Text').click()
|
||||
cy.contains('Cancel').click()
|
||||
cy.contains('Set preference and open file').should('not.exist')
|
||||
})
|
||||
|
||||
it('initially has no editors chosen', () => {
|
||||
cy.render(render, <FileOpener {...defaultPropsModal}>Open in IDE</FileOpener>)
|
||||
|
||||
cy.get('.file-opener').click()
|
||||
cy.get('input[type="radio"]').should('not.be.checked')
|
||||
cy.get('.submit').should('have.class', 'is-disabled')
|
||||
})
|
||||
|
||||
it('should not open without editor selected', () => {
|
||||
const setEditor = cy.stub()
|
||||
const openFile = cy.stub()
|
||||
|
||||
cy.render(render, <FileOpener {...defaultPropsModal} setEditor={setEditor} openFile={openFile}>Open in IDE</FileOpener>)
|
||||
|
||||
cy.get('.file-opener').click()
|
||||
cy.get('.submit')
|
||||
.should('have.class', 'is-disabled')
|
||||
.click()
|
||||
.then(() => {
|
||||
expect(setEditor).not.to.be.called
|
||||
expect(openFile).not.to.be.called
|
||||
})
|
||||
})
|
||||
|
||||
it('disables submit when Other is selected but path not entered', () => {
|
||||
const setEditor = cy.stub()
|
||||
const openFile = cy.stub()
|
||||
|
||||
cy.render(render, <FileOpener {...defaultPropsModal} setEditor={setEditor} openFile={openFile}>Open in IDE</FileOpener>)
|
||||
|
||||
cy.get('.file-opener').click()
|
||||
cy.contains('Other').click()
|
||||
cy.get('.submit')
|
||||
.should('have.class', 'is-disabled')
|
||||
.click()
|
||||
.then(() => {
|
||||
expect(setEditor).not.to.be.called
|
||||
expect(openFile).not.to.be.called
|
||||
})
|
||||
})
|
||||
|
||||
it('sets user editor when selected', () => {
|
||||
const setEditor = cy.stub()
|
||||
|
||||
cy.render(render, <FileOpener {...defaultPropsModal} setUserEditor={setEditor}>Open in IDE</FileOpener>)
|
||||
|
||||
cy.get('.file-opener').click()
|
||||
cy.contains('Sublime Text').click()
|
||||
cy.get('.submit').click().then(() => {
|
||||
expect(setEditor).to.be.calledWith(availableEditors[2])
|
||||
})
|
||||
})
|
||||
|
||||
it('opens in correct editor when selected', () => {
|
||||
const openFile = cy.stub()
|
||||
|
||||
cy.render(render, <FileOpener {...defaultPropsModal} openFile={openFile}>Open in IDE</FileOpener>)
|
||||
|
||||
cy.get('.file-opener').click()
|
||||
cy.contains('Sublime Text').click()
|
||||
cy.get('.submit').click().then(() => {
|
||||
expect(openFile).to.be.calledWith(availableEditors[2], fileDetails)
|
||||
})
|
||||
})
|
||||
|
||||
it('closes modal after selection', () => {
|
||||
cy.render(render, <FileOpener {...defaultPropsModal}>Open in IDE</FileOpener>)
|
||||
|
||||
cy.get('.file-opener').click()
|
||||
cy.contains('Sublime Text').click()
|
||||
cy.get('.submit').click()
|
||||
cy.contains('Set preference and open file').should('not.exist')
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,259 +0,0 @@
|
||||
import React, { useState } from 'react'
|
||||
import { render } from 'react-dom'
|
||||
import { Select, SelectItem } from '../../src'
|
||||
|
||||
const _ = Cypress._
|
||||
|
||||
describe('<Select />', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('dist/index.html')
|
||||
cy.viewport(400, 600)
|
||||
})
|
||||
|
||||
it('optionally provide a name', () => {
|
||||
cy.render(render, (
|
||||
<>
|
||||
<Select value="v2" name="myName">
|
||||
<SelectItem value="v1" data-test="v1" />
|
||||
<SelectItem value="v2" data-test="v2" />
|
||||
<SelectItem value="v3" data-test="v3" />
|
||||
</Select>
|
||||
<br/>
|
||||
<Select value="v1">
|
||||
<SelectItem value="v1" data-test="v1" />
|
||||
<SelectItem value="v2" data-test="v2" />
|
||||
<SelectItem value="v3" data-test="v3" />
|
||||
</Select>
|
||||
</>
|
||||
))
|
||||
|
||||
cy.get('input[name="myName"]').then((el) => expect(el.length).to.eql(3))
|
||||
cy.get('input').then((els) => {
|
||||
expect(els.length).to.eql(6)
|
||||
expect(_.filter(els, (el) => el.name !== 'myName').length).to.eql(3)
|
||||
})
|
||||
})
|
||||
|
||||
it('can render multiple groups on the same page', () => {
|
||||
cy.render(render, (
|
||||
<>
|
||||
<Select value="v2" name="myName">
|
||||
<SelectItem value="v1" data-test="v1" />
|
||||
<SelectItem value="v2" data-test="v2" />
|
||||
<SelectItem value="v3" data-test="v3" />
|
||||
</Select>
|
||||
<br/>
|
||||
<Select value="v1">
|
||||
<SelectItem value="v1" data-test="v1" />
|
||||
<SelectItem value="v2" data-test="v2" />
|
||||
<SelectItem value="v3" data-test="v3" />
|
||||
</Select>
|
||||
<br/>
|
||||
<Select value="v3">
|
||||
<SelectItem value="v1" data-test="v1" />
|
||||
<SelectItem value="v2" data-test="v2" />
|
||||
<SelectItem value="v3" data-test="v3" />
|
||||
</Select>
|
||||
</>
|
||||
))
|
||||
|
||||
cy.get('input[name="myName"]').then((el) => expect(el.length).to.eql(3))
|
||||
cy.get('input').then((els) => {
|
||||
expect(els.length).to.eql(9)
|
||||
expect(_.filter(els, (el) => el.name !== 'myName').length).to.eql(6)
|
||||
expect(els[1].checked).to.be.true
|
||||
expect(els[3].checked).to.be.true
|
||||
expect(els[8].checked).to.be.true
|
||||
})
|
||||
})
|
||||
|
||||
it('only a single SelectItem is checked at a time', () => {
|
||||
const onChange = cy.stub()
|
||||
|
||||
cy.render(render, (
|
||||
<Select value="v2" onChange={onChange}>
|
||||
<SelectItem value="v1" />
|
||||
<SelectItem value="v2" />
|
||||
<SelectItem value="v3" />
|
||||
</Select>
|
||||
))
|
||||
|
||||
cy.get('[data-value="v1"]').click()
|
||||
.then(() => expect(onChange).to.be.calledWith('v1'))
|
||||
|
||||
cy.get('[data-value="v3"]').click()
|
||||
.then(() => expect(onChange).to.be.calledWith('v3'))
|
||||
})
|
||||
|
||||
it('other components are permitted as children for a <Select />', () => {
|
||||
cy.render(render, (
|
||||
<div width="100%">
|
||||
<Select value="oranges">
|
||||
<h3>Fruits</h3>
|
||||
<label><SelectItem value="apples" data-test="apples" /> apples</label>
|
||||
<label><SelectItem value="oranges" data-test="oranges" /> oranges</label>
|
||||
<h3>Vegetables</h3>
|
||||
<label><SelectItem value="apples" data-test="apples" /> carrot</label>
|
||||
<label><SelectItem value="oranges" data-test="oranges" /> potato</label>
|
||||
</Select>
|
||||
</div>
|
||||
))
|
||||
|
||||
cy.get('h3').first().contains('Fruits')
|
||||
cy.get('h3').last().contains('Vegetables')
|
||||
})
|
||||
|
||||
describe('single value selection', () => {
|
||||
it('focus-able', () => {
|
||||
cy.render(render, (
|
||||
<Select value="v2">
|
||||
<SelectItem value="v1" />
|
||||
<SelectItem value="v2" />
|
||||
<SelectItem value="v3" />
|
||||
</Select>
|
||||
))
|
||||
|
||||
cy.get('[value="v1"]').as('focused').first().focus()
|
||||
cy.window().then((win) => {
|
||||
cy.get('@focused').then((el) => {
|
||||
expect(win.document.activeElement).to.eql(el[0])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// NOTE: requires native event tab support
|
||||
// cypress-plugin-tab does not mimic the behavior of tabbing in this context exactly as the browser does
|
||||
it.skip('tabbing moves focus to the next element with a tabIndex', () => {
|
||||
cy.render(render, (
|
||||
<Select>
|
||||
<SelectItem value="v1" data-test={`v1`} />
|
||||
<input type="text"/>
|
||||
<SelectItem value="v2" data-test={`v2`} />
|
||||
<SelectItem value="v3" data-test={`v3`} />
|
||||
</Select>
|
||||
))
|
||||
|
||||
cy.get('[data-test="v1"]').focus().tab()
|
||||
cy.window().then((win) => {
|
||||
cy.get('input[type="text"]').then((el) => {
|
||||
expect(win.document.activeElement).to.eql(el[0])
|
||||
})
|
||||
})
|
||||
|
||||
cy.get('[data-test="v3"]').focus().tab({ shift: true })
|
||||
cy.window().then((win) => {
|
||||
cy.get('input[type="text"]').then((el) => {
|
||||
expect(win.document.activeElement).to.eql(el[0])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('arrow keys', () => {
|
||||
const left = 13
|
||||
const up = 38
|
||||
const right = 39
|
||||
const down = 40
|
||||
let onChange
|
||||
|
||||
beforeEach(() => {
|
||||
const Wrapper = ({ onChangeSpy }) => {
|
||||
const [selected, setSelected] = useState()
|
||||
|
||||
const onChange = (value) => {
|
||||
onChangeSpy(value)
|
||||
setSelected(value)
|
||||
}
|
||||
|
||||
return (
|
||||
<Select value={selected} onChange={onChange}>
|
||||
<SelectItem value="v1" />
|
||||
<input type="text"/>
|
||||
<SelectItem value="v2" />
|
||||
<SelectItem value="v3" />
|
||||
<SelectItem value="v4">
|
||||
<input data-cy="input" type="text" />
|
||||
</SelectItem>
|
||||
<SelectItem value="v5" />
|
||||
</Select>
|
||||
)
|
||||
}
|
||||
|
||||
onChange = cy.spy()
|
||||
|
||||
cy.render(render, <Wrapper onChangeSpy={onChange} />)
|
||||
cy.get('li').as('items')
|
||||
cy.get('[value]').as('values')
|
||||
})
|
||||
|
||||
it('left on first goes to last', () => {
|
||||
cy.get('@items').first().click().trigger('keydown', { keyCode: left, which: left })
|
||||
cy.get('@values').last().should('be.checked')
|
||||
cy.wrap(onChange).should('be.calledWith', 'v5')
|
||||
})
|
||||
|
||||
it('up on first goes to last', () => {
|
||||
cy.get('@items').first().click().trigger('keydown', { keyCode: up, which: up })
|
||||
cy.get('@values').last().should('be.checked')
|
||||
cy.wrap(onChange).should('be.calledWith', 'v5')
|
||||
})
|
||||
|
||||
it('right on last goes to first', () => {
|
||||
cy.get('@items').last().click().trigger('keydown', { keyCode: right, which: right })
|
||||
cy.get('@values').first().should('be.checked')
|
||||
cy.wrap(onChange).should('be.calledWith', 'v1')
|
||||
})
|
||||
|
||||
it('down on last goes to first', () => {
|
||||
cy.get('@items').last().click().trigger('keydown', { keyCode: down, which: down })
|
||||
cy.get('@values').first().should('be.checked')
|
||||
cy.wrap(onChange).should('be.calledWith', 'v1')
|
||||
})
|
||||
|
||||
it('left on last goes to penultimate', () => {
|
||||
cy.get('@items').last().click().trigger('keydown', { keyCode: left, which: left })
|
||||
cy.get('@values').eq(3).should('be.checked')
|
||||
cy.wrap(onChange).should('be.calledWith', 'v4')
|
||||
})
|
||||
|
||||
it('up on last goes to penultimate', () => {
|
||||
cy.get('@items').last().click().trigger('keydown', { keyCode: up, which: up })
|
||||
cy.get('@values').eq(3).should('be.checked')
|
||||
cy.wrap(onChange).should('be.calledWith', 'v4')
|
||||
})
|
||||
|
||||
it('right on first goes to second', () => {
|
||||
cy.get('@items').first().click().trigger('keydown', { keyCode: right, which: right })
|
||||
cy.get('@values').eq(1).should('be.checked')
|
||||
cy.wrap(onChange).should('be.calledWith', 'v2')
|
||||
})
|
||||
|
||||
it('down on first goes to second', () => {
|
||||
cy.get('@items').first().click().trigger('keydown', { keyCode: down, which: down })
|
||||
cy.get('@values').eq(1).should('be.checked')
|
||||
cy.wrap(onChange).should('be.calledWith', 'v2')
|
||||
})
|
||||
|
||||
describe('when keydown comes from inner element', () => {
|
||||
it('does not move on left', () => {
|
||||
cy.get('[data-cy="input"]').type('{leftarrow}')
|
||||
cy.get('@values').eq(3).should('be.checked')
|
||||
})
|
||||
|
||||
it('does not move on right', () => {
|
||||
cy.get('[data-cy="input"]').type('{rightarrow}')
|
||||
cy.get('@values').eq(3).should('be.checked')
|
||||
})
|
||||
|
||||
it('does not move on up', () => {
|
||||
cy.get('[data-cy="input"]').type('{uparrow}')
|
||||
cy.get('@values').eq(3).should('be.checked')
|
||||
})
|
||||
|
||||
it('does not move on down', () => {
|
||||
cy.get('[data-cy="input"]').type('{downarrow}')
|
||||
cy.get('@values').eq(3).should('be.checked')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,3 +0,0 @@
|
||||
Cypress.Commands.add('render', (r, component) => {
|
||||
cy.window().invoke('renderComponent', (el) => r(component, el))
|
||||
})
|
||||
@@ -1 +0,0 @@
|
||||
<div id="app"></div>
|
||||
@@ -1,4 +0,0 @@
|
||||
import './test-entry.scss'
|
||||
import '../../src/browser-icon' // ensures browser icon images load
|
||||
|
||||
window.renderComponent = (r) => r(document.getElementById('app'))
|
||||
@@ -1,8 +0,0 @@
|
||||
@import "~@fortawesome/fontawesome-free/scss/regular.scss";
|
||||
@import "~@fortawesome/fontawesome-free/scss/solid.scss";
|
||||
@import "~@fortawesome/fontawesome-free/scss/brands.scss";
|
||||
@import "~@fortawesome/fontawesome-free/scss/fontawesome.scss";
|
||||
|
||||
@import '~@reach/dialog/styles.css';
|
||||
@import '../../src/dropdown';
|
||||
@import '../../src/file-opener/file-opener';
|
||||
@@ -1,7 +0,0 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
7
packages/ui-components/index.d.ts
vendored
7
packages/ui-components/index.d.ts
vendored
@@ -1,7 +0,0 @@
|
||||
/// <reference path="../../cli/types/cy-blob-util.d.ts" />
|
||||
/// <reference path="../../cli/types/cy-bluebird.d.ts" />
|
||||
/// <reference path="../../cli/types/cy-minimatch.d.ts" />
|
||||
|
||||
/// <reference path="../../cli/types/cypress.d.ts" />
|
||||
/// <reference path="../../cli/types/cypress-global-vars.d.ts" />
|
||||
/// <reference path="../../cli/types/cypress-type-helpers.d.ts" />
|
||||
@@ -1,44 +0,0 @@
|
||||
{
|
||||
"name": "@packages/ui-components",
|
||||
"version": "0.0.0-development",
|
||||
"private": true,
|
||||
"main": "src/index.tsx",
|
||||
"scripts": {
|
||||
"build-for-tests": "node ../../scripts/run-webpack",
|
||||
"check-deps": "node ../../scripts/check-deps.js --verbose",
|
||||
"check-deps-pre": "npm run check-deps -- --prescript",
|
||||
"clean-deps": "rimraf node_modules",
|
||||
"cypress:open": "node ../../scripts/cypress open --project .",
|
||||
"cypress:run": "node ../../scripts/cypress run --project .",
|
||||
"pretest": "npm run check-deps-pre",
|
||||
"watch": "npm run build-for-tests -- --watch --progress"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.9.0",
|
||||
"@babel/plugin-proposal-class-properties": "7.8.3",
|
||||
"@babel/plugin-proposal-decorators": "7.8.3",
|
||||
"@babel/preset-env": "7.9.0",
|
||||
"@babel/preset-react": "7.9.4",
|
||||
"@cypress/react-tooltip": "^0.5.3",
|
||||
"@cypress/webpack-preprocessor": "0.0.0-development",
|
||||
"@fortawesome/fontawesome-free": "6.0.0",
|
||||
"@percy/core": "^1.0.0-beta.48",
|
||||
"@percy/cypress": "^3.1.0",
|
||||
"@reach/dialog": "0.10.5",
|
||||
"@reach/visually-hidden": "0.10.4",
|
||||
"babel-loader": "8.1.0",
|
||||
"browser-logos": "github:alrra/browser-logos",
|
||||
"chai-subset": "1.6.0",
|
||||
"classnames": "2.3.1",
|
||||
"file-loader": "4.3.0",
|
||||
"lodash": "^4.17.19",
|
||||
"mobx": "5.15.4",
|
||||
"mobx-react": "6.1.7",
|
||||
"prop-types": "15.7.2",
|
||||
"react": "16.8.6",
|
||||
"react-dom": "16.8.6",
|
||||
"rimraf": "3.0.2",
|
||||
"webpack": "^4.44.2",
|
||||
"webpack-cli": "3.3.2"
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"extends": [
|
||||
"plugin:@cypress/dev/react",
|
||||
"plugin:@cypress/dev/tests"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"settings": {
|
||||
"react": {
|
||||
"version": "16.12"
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"arrow-body-style": "off",
|
||||
"no-unused-vars": "off",
|
||||
"react/jsx-filename-extension": [
|
||||
"warn",
|
||||
{
|
||||
"extensions": [
|
||||
".js",
|
||||
".jsx",
|
||||
".tsx"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
import _ from 'lodash'
|
||||
import React from 'react'
|
||||
|
||||
interface FamilyOptions {
|
||||
[key: string]: RegExp
|
||||
}
|
||||
|
||||
const families: FamilyOptions = {
|
||||
chrome: /^chrome/i,
|
||||
chromium: /^chromium/i,
|
||||
edge: /^edge/i,
|
||||
electron: /^electron/i,
|
||||
firefox: /^firefox/i,
|
||||
}
|
||||
|
||||
interface LogoOptions {
|
||||
[key: string]: string
|
||||
}
|
||||
|
||||
const logoPaths: LogoOptions = {
|
||||
canary: require('browser-logos/src/chrome-canary/chrome-canary_32x32.png'),
|
||||
chrome: require('browser-logos/src/chrome/chrome_32x32.png'),
|
||||
chromeBeta: require('browser-logos/src/chrome-beta/chrome-beta_32x32.png'),
|
||||
chromium: require('browser-logos/src/chromium/chromium_32x32.png'),
|
||||
edge: require('browser-logos/src/edge/edge_32x32.png'),
|
||||
edgeBeta: require('browser-logos/src/edge-beta/edge-beta_32x32.png'),
|
||||
edgeCanary: require('browser-logos/src/edge-canary/edge-canary_32x32.png'),
|
||||
edgeDev: require('browser-logos/src/edge-dev/edge-dev_32x32.png'),
|
||||
electron: require('browser-logos/src/electron/electron_32x32.png'),
|
||||
firefox: require('browser-logos/src/firefox/firefox_32x32.png'),
|
||||
firefoxDeveloperEdition: require('browser-logos/src/firefox-developer-edition/firefox-developer-edition_32x32.png'),
|
||||
firefoxNightly: require('browser-logos/src/firefox-nightly/firefox-nightly_32x32.png'),
|
||||
}
|
||||
|
||||
const familyFallback = (browserKey: string) => {
|
||||
return _.reduce(families, (found, regex, family) => {
|
||||
if (found !== '') return found
|
||||
|
||||
if (regex.test(browserKey)) return family
|
||||
|
||||
return ''
|
||||
}, '')
|
||||
}
|
||||
|
||||
const logoPath = (browserName: string) => {
|
||||
const browserKey = _.camelCase(browserName)
|
||||
|
||||
return logoPaths[browserKey] || logoPaths[familyFallback(browserKey)]
|
||||
}
|
||||
|
||||
interface Props {
|
||||
browserName: string
|
||||
}
|
||||
|
||||
// browserName should be the browser's display name
|
||||
const BrowserIcon = ({ browserName }: Props) => {
|
||||
if (logoPath(browserName)) {
|
||||
return <img className='browser-icon' src={logoPath(browserName)} alt={browserName} />
|
||||
}
|
||||
|
||||
return <i className='browser-icon fas fa-fw fa-globe' />
|
||||
}
|
||||
|
||||
export default BrowserIcon
|
||||
@@ -1,65 +0,0 @@
|
||||
.dropdown {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.dropdown-chosen {
|
||||
background: none;
|
||||
border: none;
|
||||
outline: none;
|
||||
|
||||
&.disabled {
|
||||
pointer-events: none;
|
||||
opacity: 0.65;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-caret {
|
||||
border-top: 4px dashed;
|
||||
border-right: 4px solid transparent;
|
||||
border-left: 4px solid transparent;
|
||||
border-width: 5px 5px 0;
|
||||
display: inline-block;
|
||||
height: 0;
|
||||
vertical-align: middle;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
background-clip: padding-box;
|
||||
background-color: #fff;
|
||||
border: 1px solid rgba(0, 0, 0, 0.15);
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
|
||||
font-size: 14px;
|
||||
display: none;
|
||||
float: left;
|
||||
left: 0;
|
||||
margin: 0;
|
||||
min-width: 160px;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
list-style: none;
|
||||
text-align: left;
|
||||
z-index: 2000;
|
||||
|
||||
.open & {
|
||||
display: block;
|
||||
}
|
||||
|
||||
li {
|
||||
&:last-of-type {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus,
|
||||
&:active {
|
||||
cursor: pointer;
|
||||
background-color: #f5f5f5;
|
||||
color: #262626;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
import cs from 'classnames'
|
||||
import _ from 'lodash'
|
||||
import React, { Component, ReactNode } from 'react'
|
||||
import { findDOMNode } from 'react-dom'
|
||||
|
||||
interface Indexable {
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
interface Props {
|
||||
className?: string
|
||||
chosen: Indexable
|
||||
others: Indexable[]
|
||||
onSelect: (item: Indexable) => any
|
||||
renderItem: (item: Indexable) => ReactNode
|
||||
keyProperty: string
|
||||
disabled?: boolean
|
||||
document: Document
|
||||
}
|
||||
|
||||
class Dropdown extends Component<Props> {
|
||||
static defaultProps = {
|
||||
className: '',
|
||||
document,
|
||||
}
|
||||
|
||||
state = { open: false }
|
||||
|
||||
outsideClickHandler: (e: Event) => void = () => {}
|
||||
|
||||
componentDidMount () {
|
||||
this.outsideClickHandler = (e: Event) => {
|
||||
if (!findDOMNode(this)?.contains(e.target as Node)) {
|
||||
this.setState({ open: false })
|
||||
}
|
||||
}
|
||||
|
||||
this.props.document.body.addEventListener('click', this.outsideClickHandler)
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
this.props.document.body.removeEventListener('click', this.outsideClickHandler)
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<li className={cs('dropdown', this.props.className, { open: this.state.open })}>
|
||||
{this._button()}
|
||||
{this._items()}
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
_button () {
|
||||
if (this.props.others.length) {
|
||||
return (
|
||||
<button onClick={this._toggleOpen} className={cs('dropdown-chosen', { disabled: this.props.disabled })}>
|
||||
{this._buttonContent()}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<span>
|
||||
{this._buttonContent()}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
_buttonContent () {
|
||||
return (
|
||||
<>
|
||||
{this.props.renderItem(this.props.chosen)}{' '}
|
||||
{this._caret()}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
_caret () {
|
||||
if (!this.props.others.length || this.props.disabled) return null
|
||||
|
||||
return (
|
||||
<span className='dropdown-toggle'>
|
||||
<span className='dropdown-caret' />
|
||||
<span className='sr-only'>Toggle Dropdown</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
_toggleOpen = () => {
|
||||
this.setState({ open: !this.state.open })
|
||||
}
|
||||
|
||||
_items () {
|
||||
if (!this.props.others.length || this.props.disabled) return null
|
||||
|
||||
return (
|
||||
<ul className='dropdown-menu'>
|
||||
{_.map(this.props.others, (item) => (
|
||||
<li
|
||||
key={item[this.props.keyProperty]}
|
||||
tabIndex={0}
|
||||
onClick={() => this._onSelect(item)}
|
||||
>{this.props.renderItem(item)}</li>
|
||||
))}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
|
||||
_onSelect (item: object) {
|
||||
const retval = this.props.onSelect(item)
|
||||
const open = _.isBoolean(retval) ? retval : false
|
||||
|
||||
this.setState({ open })
|
||||
}
|
||||
}
|
||||
|
||||
export default Dropdown
|
||||
@@ -1,96 +0,0 @@
|
||||
import _ from 'lodash'
|
||||
import { Dialog } from '@reach/dialog'
|
||||
import { action } from 'mobx'
|
||||
import { observer, useLocalStore } from 'mobx-react'
|
||||
// @ts-ignore
|
||||
import Tooltip from '@cypress/react-tooltip'
|
||||
|
||||
import cs from 'classnames'
|
||||
import React from 'react'
|
||||
import VisuallyHidden from '@reach/visually-hidden'
|
||||
|
||||
import EditorPicker from './editor-picker'
|
||||
import { Editor } from './file-model'
|
||||
|
||||
interface Props {
|
||||
chosenEditor: Editor
|
||||
editors: Editor[]
|
||||
isOpen: boolean
|
||||
onClose: (() => void)
|
||||
onSetChosenEditor: ((editor: Editor) => void)
|
||||
onSetEditor: ((editor: Editor) => void)
|
||||
}
|
||||
|
||||
const validate = (chosenEditor: Editor) => {
|
||||
let isValid = !!chosenEditor && !!chosenEditor.id
|
||||
let validationMessage = 'Please select a preference'
|
||||
|
||||
if (isValid && chosenEditor.isOther && !chosenEditor.binary) {
|
||||
isValid = false
|
||||
validationMessage = 'Please enter the path for the "Other" editor'
|
||||
}
|
||||
|
||||
return {
|
||||
isValid,
|
||||
validationMessage,
|
||||
}
|
||||
}
|
||||
|
||||
const EditorPickerModal = observer(({ chosenEditor, editors, isOpen, onClose, onSetChosenEditor, onSetEditor }: Props) => {
|
||||
const state = useLocalStore((external) => ({
|
||||
setOtherPath: action((otherPath: string) => {
|
||||
const otherOption = _.find(external.editors, { isOther: true })
|
||||
|
||||
if (otherOption) {
|
||||
otherOption.binary = otherPath
|
||||
}
|
||||
}),
|
||||
}), { editors })
|
||||
|
||||
const setEditor = () => {
|
||||
const { isValid } = validate(chosenEditor)
|
||||
|
||||
if (!isValid) return
|
||||
|
||||
onSetEditor(chosenEditor)
|
||||
}
|
||||
|
||||
if (!editors.length) return null
|
||||
|
||||
const { isValid, validationMessage } = validate(chosenEditor)
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
className='editor-picker-modal'
|
||||
aria-label="Explanation of choosing an editor"
|
||||
isOpen={isOpen}
|
||||
onDismiss={onClose}
|
||||
>
|
||||
<div className='content'>
|
||||
<h1>File Opener Preference</h1>
|
||||
<p>Please select your preference for opening files on your system.</p>
|
||||
<EditorPicker
|
||||
chosen={chosenEditor}
|
||||
editors={editors}
|
||||
onSelect={onSetChosenEditor}
|
||||
onUpdateOtherPath={state.setOtherPath}
|
||||
/>
|
||||
<p>We will use your selected preference to open files in the future. You can change your preference in the <b>Settings</b> tab of the Cypress Test Runner.</p>
|
||||
</div>
|
||||
<div className='controls'>
|
||||
<Tooltip title={validationMessage} visible={isValid ? false : undefined} className='cy-tooltip'>
|
||||
<button className={cs('submit', { 'is-disabled': !isValid })} onClick={setEditor}>Set preference and open file</button>
|
||||
</Tooltip>
|
||||
<button className='cancel' onClick={onClose}>Cancel</button>
|
||||
</div>
|
||||
<button className='close-button' onClick={onClose}>
|
||||
<VisuallyHidden>Close</VisuallyHidden>
|
||||
<span aria-hidden>
|
||||
<i className='fas fa-times' />
|
||||
</span>
|
||||
</button>
|
||||
</Dialog>
|
||||
)
|
||||
})
|
||||
|
||||
export default EditorPickerModal
|
||||
@@ -1,56 +0,0 @@
|
||||
import _ from 'lodash'
|
||||
import { observer } from 'mobx-react'
|
||||
import React, { ChangeEvent } from 'react'
|
||||
|
||||
import { Editor } from './file-model'
|
||||
import { Select, SelectItem } from '../select'
|
||||
|
||||
interface Props {
|
||||
chosen?: Partial<Editor>
|
||||
editors: Editor[]
|
||||
onSelect: (editor: Editor) => any
|
||||
onUpdateOtherPath: (path: string) => any
|
||||
}
|
||||
|
||||
const EditorPicker = observer(({ chosen = {}, editors, onSelect, onUpdateOtherPath }: Props) => {
|
||||
const editorOptions = _.reject(editors, { isOther: true })
|
||||
const otherOption = _.find(editors, { isOther: true })
|
||||
|
||||
const onChange = (id: string) => {
|
||||
const editor = _.find(editors, { id })
|
||||
|
||||
editor && onSelect(editor)
|
||||
}
|
||||
|
||||
const updateOtherPath = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
onUpdateOtherPath(_.trim(event.target.value || ''))
|
||||
}
|
||||
|
||||
const otherInput = (
|
||||
<input
|
||||
type='text'
|
||||
className='other-input'
|
||||
value={otherOption?.binary || ''}
|
||||
onFocus={_.partial(onChange, 'other')}
|
||||
onChange={updateOtherPath}
|
||||
/>
|
||||
)
|
||||
|
||||
return (
|
||||
<Select value={chosen.id || ''} className='editor-picker' name='editor-picker' onChange={onChange}>
|
||||
{_.map(editorOptions, (editor) => (
|
||||
<SelectItem key={editor.id} value={editor.id}>
|
||||
{editor.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
{otherOption && (
|
||||
<SelectItem value={otherOption.id}>
|
||||
{otherOption.name}: {otherInput}
|
||||
{chosen.isOther && <span className='description'>Enter the full path to your editor's executable</span>}
|
||||
</SelectItem>
|
||||
)}
|
||||
</Select>
|
||||
)
|
||||
})
|
||||
|
||||
export default EditorPicker
|
||||
@@ -1,12 +0,0 @@
|
||||
export interface Editor {
|
||||
id: string
|
||||
name: string
|
||||
binary: string
|
||||
isOther: boolean
|
||||
description?: string
|
||||
}
|
||||
|
||||
export interface GetUserEditorResult {
|
||||
preferredOpener?: Editor
|
||||
availableEditors?: Editor[]
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
@import '../select/select';
|
||||
|
||||
$pass: #08c18d !default;
|
||||
$font-sans: 'Fira Mono', 'Helvetica Neue', 'Arial', sans-serif;
|
||||
|
||||
.editor-picker {
|
||||
label {
|
||||
align-items: flex-start;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.other-input {
|
||||
border: solid 1px #7e7e7e;
|
||||
border-radius: 3px;
|
||||
margin-left: 0.3em;
|
||||
padding: 0.2em 0.4em;
|
||||
}
|
||||
|
||||
.is-selected .other-input {
|
||||
flex-grow: 2;
|
||||
}
|
||||
|
||||
.description {
|
||||
color: #7e7e7e;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
i.description {
|
||||
margin-left: 0.4em;
|
||||
margin-top: 0.1em;
|
||||
}
|
||||
|
||||
span.description {
|
||||
display: block;
|
||||
padding-left: 5.2em;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.editor-picker-modal {
|
||||
max-width: 40em;
|
||||
|
||||
.editor-picker {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.controls {
|
||||
> span:first-child {
|
||||
order: 1;
|
||||
}
|
||||
|
||||
button.is-disabled,
|
||||
button.is-disabled:hover,
|
||||
button.is-disabled:focus {
|
||||
background: $pass !important;
|
||||
cursor: default !important;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
padding: 1em 1em 1em;
|
||||
}
|
||||
}
|
||||
|
||||
[data-reach-dialog-overlay] {
|
||||
display: flex;
|
||||
padding: 2em 0;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
[data-reach-dialog-content] {
|
||||
align-items: center;
|
||||
background: #f8f8f8;
|
||||
border-radius: 10px;
|
||||
font-size: 0.9em;
|
||||
justify-content: center;
|
||||
margin: auto;
|
||||
min-width: 30em;
|
||||
padding: 2em 0 0;
|
||||
position: relative;
|
||||
|
||||
@if variable-exists(open-sans) {
|
||||
font-family: $open-sans;
|
||||
} @else {
|
||||
font-family: $font-sans;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.5em;
|
||||
padding-bottom: 0.5em;
|
||||
}
|
||||
|
||||
button {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 1em;
|
||||
padding: 0.6em 1em;
|
||||
line-height: 1em;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 1.5;
|
||||
margin-bottom: 1em;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 0 1.2em 0.6em;
|
||||
}
|
||||
|
||||
.controls {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 0.6em;
|
||||
|
||||
button {
|
||||
border-radius: 3px;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
.submit {
|
||||
background: $pass;
|
||||
color: #fff;
|
||||
margin-left: 0.6em;
|
||||
order: 1;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background: darken($pass, 10%);
|
||||
}
|
||||
}
|
||||
|
||||
.cancel {
|
||||
background: #e3e3e3;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background: darken(#e3e3e3, 10%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.close-button {
|
||||
position: absolute;
|
||||
right: 0.1em;
|
||||
top: 0.5em;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
import _ from 'lodash'
|
||||
import { action } from 'mobx'
|
||||
import { observer, useLocalStore } from 'mobx-react'
|
||||
import React, { MouseEvent, ReactNode } from 'react'
|
||||
|
||||
import EditorPickerModal from './editor-picker-modal'
|
||||
import { GetUserEditorResult, Editor } from './file-model'
|
||||
import type { FileDetails } from '@packages/types'
|
||||
|
||||
interface Props {
|
||||
children: ReactNode
|
||||
fileDetails: FileDetails
|
||||
openFile: (where: Editor, absoluteFile: FileDetails) => any
|
||||
getUserEditor: (callback: (result: GetUserEditorResult) => void) => any
|
||||
setUserEditor: (editor: Editor) => any
|
||||
className?: string
|
||||
}
|
||||
|
||||
const FileOpener = observer(({ children, fileDetails, openFile, getUserEditor, setUserEditor, className }: Props) => {
|
||||
const state = useLocalStore(() => ({
|
||||
editors: [] as Editor[],
|
||||
chosenEditor: {} as Editor,
|
||||
isLoadingEditor: false,
|
||||
isModalOpen: false,
|
||||
setChosenEditor: action((editor: Editor) => {
|
||||
state.chosenEditor = editor
|
||||
}),
|
||||
setEditors: action((editors: Editor[]) => {
|
||||
state.editors = editors
|
||||
}),
|
||||
setIsLoadingEditor: action((isLoading: boolean) => {
|
||||
state.isLoadingEditor = isLoading
|
||||
}),
|
||||
setIsModalOpen: action((isOpen: boolean) => {
|
||||
state.isModalOpen = isOpen
|
||||
}),
|
||||
}))
|
||||
|
||||
const attemptOpenFile = (e: MouseEvent) => {
|
||||
e.preventDefault()
|
||||
|
||||
if (state.isLoadingEditor) return
|
||||
|
||||
state.setIsLoadingEditor(true)
|
||||
|
||||
// TODO: instead of the back-n-forth, send 'open:file' or similar, and if the
|
||||
// user editor isn't set, it should send back the available editors
|
||||
getUserEditor((result: GetUserEditorResult) => {
|
||||
state.setIsLoadingEditor(false)
|
||||
|
||||
if (result.preferredOpener) {
|
||||
return openFile(result.preferredOpener, fileDetails)
|
||||
}
|
||||
|
||||
state.setEditors(result.availableEditors || [])
|
||||
state.setIsModalOpen(true)
|
||||
})
|
||||
}
|
||||
|
||||
const setEditor = (editor: Editor) => {
|
||||
setUserEditor(editor)
|
||||
state.setIsModalOpen(false)
|
||||
state.setChosenEditor({} as Editor)
|
||||
openFile(editor, fileDetails)
|
||||
}
|
||||
|
||||
return (
|
||||
<a className={className} onClick={attemptOpenFile} href='#'>
|
||||
{children}
|
||||
<EditorPickerModal
|
||||
chosenEditor={state.chosenEditor}
|
||||
editors={state.editors}
|
||||
isOpen={state.isModalOpen}
|
||||
onSetEditor={setEditor}
|
||||
onSetChosenEditor={state.setChosenEditor}
|
||||
onClose={_.partial(state.setIsModalOpen, false)}
|
||||
/>
|
||||
</a>
|
||||
)
|
||||
})
|
||||
|
||||
export default FileOpener
|
||||
@@ -1,13 +0,0 @@
|
||||
export { default as BrowserIcon } from './browser-icon'
|
||||
|
||||
export { default as Dropdown } from './dropdown'
|
||||
|
||||
export { default as EditorPicker } from './file-opener/editor-picker'
|
||||
|
||||
export { default as EditorPickerModal } from './file-opener/editor-picker-modal'
|
||||
|
||||
export { default as FileOpener } from './file-opener/file-opener'
|
||||
|
||||
export * from './file-opener/file-model'
|
||||
|
||||
export * from './select'
|
||||
@@ -1,17 +0,0 @@
|
||||
import _ from 'lodash'
|
||||
import { createContext } from 'react'
|
||||
import type { KeyboardEvent } from 'react'
|
||||
|
||||
interface ContextValue {
|
||||
handleChange: (value: string) => any
|
||||
handleKeyDown: (event: KeyboardEvent) => any
|
||||
isSelected: (value: string) => boolean
|
||||
name: string
|
||||
}
|
||||
|
||||
export default createContext<ContextValue>({
|
||||
handleChange: _.noop,
|
||||
handleKeyDown: _.noop,
|
||||
isSelected: () => false,
|
||||
name: '',
|
||||
})
|
||||
@@ -1,5 +0,0 @@
|
||||
export { default as SelectItem } from './select-item'
|
||||
|
||||
export { default as Select } from './select-group'
|
||||
|
||||
export { default as useSelect } from './use-select'
|
||||
@@ -1,78 +0,0 @@
|
||||
import cs from 'classnames'
|
||||
import React, { Children, KeyboardEvent, ReactElement, ReactNode, useCallback, useMemo } from 'react'
|
||||
import _ from 'lodash'
|
||||
import Context from './context'
|
||||
|
||||
const generateGroupName = (name?: string) => {
|
||||
if (name) {
|
||||
return name
|
||||
}
|
||||
|
||||
return _.uniqueId('Select-')
|
||||
}
|
||||
|
||||
const toValues = (children: ReactNode[]) => {
|
||||
const withSelectItem = _.filter(children, (child: ReactElement) => {
|
||||
return child.props.selectItem
|
||||
})
|
||||
|
||||
return _.map<any, string>(withSelectItem, (child: ReactElement) => child.props.value)
|
||||
}
|
||||
|
||||
const left = 13
|
||||
const up = 38
|
||||
const right = 39
|
||||
const down = 40
|
||||
|
||||
interface Props {
|
||||
children: ReactNode
|
||||
className?: string
|
||||
name?: string
|
||||
onChange?: (value: string) => any
|
||||
value: string
|
||||
}
|
||||
|
||||
const Select = ({ children, className, name, onChange = _.noop, value }: Props) => {
|
||||
const allValues = useMemo(() => toValues(Children.toArray(children)), [children])
|
||||
|
||||
const handleKeyDown = useCallback(({ keyCode }: KeyboardEvent) => {
|
||||
if (![left, up, right, down].includes(keyCode)) {
|
||||
return
|
||||
}
|
||||
|
||||
const currentIndex = _.findIndex(allValues, (v) => v === value)
|
||||
|
||||
if (currentIndex === -1) {
|
||||
onChange(allValues[0])
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if ([left, up].includes(keyCode)) {
|
||||
const incrementedIndex = currentIndex - 1
|
||||
|
||||
const newIndex = incrementedIndex < 0 ? (Math.abs(incrementedIndex) + allValues.length - 2) : (incrementedIndex) % (allValues.length)
|
||||
|
||||
onChange(allValues[newIndex])
|
||||
} else if ([right, down].includes(keyCode)) {
|
||||
const newIndex = (currentIndex + 1) % (allValues.length)
|
||||
|
||||
onChange(allValues[newIndex])
|
||||
}
|
||||
}, [allValues, value])
|
||||
|
||||
return (
|
||||
<Context.Provider value={{
|
||||
handleChange: onChange,
|
||||
handleKeyDown,
|
||||
isSelected: (v) => v === value,
|
||||
name: generateGroupName(name),
|
||||
}}>
|
||||
<ul className={cs('select', className)}>
|
||||
{children}
|
||||
</ul>
|
||||
</Context.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export default Select
|
||||
@@ -1,63 +0,0 @@
|
||||
import cs from 'classnames'
|
||||
import React, { KeyboardEvent, ReactNode, useRef } from 'react'
|
||||
import { partial, uniqueId } from 'lodash'
|
||||
import VisuallyHidden from '@reach/visually-hidden'
|
||||
|
||||
import useSelect from './use-select'
|
||||
|
||||
interface Props {
|
||||
value: string
|
||||
children?: ReactNode
|
||||
selectItem?: boolean
|
||||
}
|
||||
|
||||
const SelectItem = ({ value, children, ...rest }: Props) => {
|
||||
const { name, handleChange, handleKeyDown, isSelected } = useSelect()
|
||||
const liRef = useRef(null)
|
||||
const inputRef = useRef(null)
|
||||
const id = uniqueId('select-item-')
|
||||
|
||||
const onKeyDown = (e: KeyboardEvent) => {
|
||||
// ensure it's not an element in children that's being keyed down
|
||||
if (e.target && e.target !== liRef.current && e.target !== inputRef.current) {
|
||||
return
|
||||
}
|
||||
|
||||
handleKeyDown(e)
|
||||
}
|
||||
|
||||
return (<li
|
||||
className={cs('select-item', { 'is-selected': isSelected(value) })}
|
||||
ref={liRef}
|
||||
onClick={partial(handleChange, value)}
|
||||
onKeyDown={onKeyDown}
|
||||
data-value={value}
|
||||
>
|
||||
<label htmlFor={id}>
|
||||
<i className='select-item-indicator fa' />
|
||||
<VisuallyHidden>
|
||||
<input
|
||||
{...rest}
|
||||
id={id}
|
||||
ref={inputRef}
|
||||
checked={isSelected(value)}
|
||||
onChange={partial(handleChange, value)}
|
||||
onKeyDown={onKeyDown}
|
||||
name={name}
|
||||
type='radio'
|
||||
value={value}
|
||||
// style required to prevent an error from being thrown
|
||||
// when used inside of a dialog (ex. editor picker modal)
|
||||
style={{ margin: 0 }}
|
||||
/>
|
||||
</VisuallyHidden>
|
||||
{children}
|
||||
</label>
|
||||
</li>)
|
||||
}
|
||||
|
||||
SelectItem.defaultProps = {
|
||||
selectItem: true,
|
||||
}
|
||||
|
||||
export default SelectItem
|
||||
@@ -1,42 +0,0 @@
|
||||
.select-item {
|
||||
border-radius: 3px;
|
||||
border: solid 2px transparent;
|
||||
cursor: pointer;
|
||||
margin: 0.2em 0;
|
||||
padding: 0.2em 0.4em;
|
||||
|
||||
label {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.select-item-indicator {
|
||||
@extend .far;
|
||||
@extend .#{$fa-css-prefix}-circle;
|
||||
color: #999;
|
||||
margin-right: 0.5em;
|
||||
position: relative;
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background: #fff;
|
||||
|
||||
.select-item-indicator {
|
||||
@extend .fas;
|
||||
@extend .#{$fa-css-prefix}-circle;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-selected {
|
||||
background: #fff;
|
||||
border-color: #08c18d;
|
||||
|
||||
.select-item-indicator {
|
||||
@extend .fas;
|
||||
@extend .#{$fa-css-prefix}-circle;
|
||||
color: #08c18d;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
import { useContext } from 'react'
|
||||
import context from './context'
|
||||
|
||||
export default () => useContext(context)
|
||||
@@ -1,57 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Basic Options */
|
||||
"target": "es2015",
|
||||
"module": "commonjs",
|
||||
/*
|
||||
* Allow javascript files to be compiled.
|
||||
* Override this in modules that need JS
|
||||
*/
|
||||
"allowJs": true,
|
||||
"jsx": "react",
|
||||
"noImplicitAny": false,
|
||||
"noImplicitThis": false,
|
||||
"preserveWatchOutput": true,
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
||||
/* Generates corresponding '.d.ts' file. */
|
||||
// "declaration": true,
|
||||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||
/* Generates corresponding '.map' file. */
|
||||
"sourceMap": true,
|
||||
/* Import emit helpers from 'tslib'. */
|
||||
"importHelpers": true,
|
||||
"strictNullChecks": true,
|
||||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||
/* Strict Type-Checking Options */
|
||||
// "traceResolution": true,
|
||||
"strict": false,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
/**
|
||||
* Skip type checking of all declaration files (*.d.ts).
|
||||
* TODO: Look into changing this in the future
|
||||
*/
|
||||
/* Additional Checks */
|
||||
/* Report errors on unused locals. */
|
||||
// "noEmit": true,
|
||||
"noUnusedLocals": false,
|
||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||
/* Report error when not all code paths in function return a value. */
|
||||
"noImplicitReturns": true,
|
||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||
/* Module Resolution Options */
|
||||
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||
// "baseUrl": "../", /* Base directory to resolve non-absolute module names. */
|
||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||
// "rootDirs": ["../driver/src"], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
"types": [], /* Type declaration files to be included in compilation. */
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"esModuleInterop": true,
|
||||
"noErrorTruncation": true,
|
||||
"experimentalDecorators": true,
|
||||
},
|
||||
"exclude": [
|
||||
"dist"
|
||||
]
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
import { getCommonConfig, HtmlWebpackPlugin } from '@packages/web-config/webpack.config.base'
|
||||
import path from 'path'
|
||||
import webpack from 'webpack'
|
||||
|
||||
// @ts-ignore
|
||||
const config: webpack.Configuration = {
|
||||
...getCommonConfig(),
|
||||
entry: {
|
||||
components: [path.resolve(__dirname, 'cypress', 'support', 'test-entry.jsx')],
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: '[name].js',
|
||||
devtoolModuleFilenameTemplate: 'cypress://[namespace]/[resource-path]',
|
||||
},
|
||||
}
|
||||
|
||||
config.plugins = [
|
||||
// @ts-ignore
|
||||
...config.plugins,
|
||||
new HtmlWebpackPlugin({
|
||||
template: path.resolve(__dirname, 'cypress/support/test-entry.html'),
|
||||
}),
|
||||
]
|
||||
|
||||
export default config
|
||||
@@ -32,6 +32,5 @@ export const monorepoPaths = {
|
||||
pkgSocket: path.join(__dirname, '../../packages/socket'),
|
||||
pkgTs: path.join(__dirname, '../../packages/ts'),
|
||||
pkgTypes: path.join(__dirname, '../../packages/types'),
|
||||
pkgUiComponents: path.join(__dirname, '../../packages/ui-components'),
|
||||
pkgWebConfig: path.join(__dirname, '../../packages/web-config')
|
||||
} as const
|
||||
|
||||
94
yarn.lock
94
yarn.lock
@@ -2406,7 +2406,7 @@
|
||||
check-more-types "2.24.0"
|
||||
lazy-ass "1.6.0"
|
||||
|
||||
"@cypress/react-tooltip@0.5.3", "@cypress/react-tooltip@^0.5.3":
|
||||
"@cypress/react-tooltip@0.5.3":
|
||||
version "0.5.3"
|
||||
resolved "https://registry.yarnpkg.com/@cypress/react-tooltip/-/react-tooltip-0.5.3.tgz#3e0635304b2bf7dab5b7c251eb1ad23048b05dac"
|
||||
integrity sha512-5/CkKmEtirHAsMh8B6vdzcRHVAYsspviQhv8aw4S+DM/RjAdxALiof8nw941GfmWzgu8qDXGkxgKvv3oxZrfNw==
|
||||
@@ -5418,6 +5418,14 @@
|
||||
"@percy/client" "1.2.0"
|
||||
"@percy/logger" "1.2.0"
|
||||
|
||||
"@percy/client@1.10.4":
|
||||
version "1.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@percy/client/-/client-1.10.4.tgz#558ec16d8780d6513881da8550d453e390571d63"
|
||||
integrity sha512-TQq4TOL86cXZUoLhz4mje0OAvQtxjNZIpYLvhJ5ekOdFrBuU5xXVegXjAQRTN90SokPT80/lPfRVwQgsaBaXSw==
|
||||
dependencies:
|
||||
"@percy/env" "1.10.4"
|
||||
"@percy/logger" "1.10.4"
|
||||
|
||||
"@percy/client@1.2.0":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@percy/client/-/client-1.2.0.tgz#d7d7f06c98fbd1d7c6ecf2a3200080d9fdae6595"
|
||||
@@ -5426,13 +5434,15 @@
|
||||
"@percy/env" "1.2.0"
|
||||
"@percy/logger" "1.2.0"
|
||||
|
||||
"@percy/client@1.8.1":
|
||||
version "1.8.1"
|
||||
resolved "https://registry.yarnpkg.com/@percy/client/-/client-1.8.1.tgz#bbc81c2a41ab44e5f79c93aac6afa68c17a90af8"
|
||||
integrity sha512-2T0SdIUFwMCsnaUTM0hNQx5lrkg2qPHPKBL/MRrbbTPJVJe3J9PzeR84RJtKviyy+ciEkkm6UaQsWBngbyXXsQ==
|
||||
"@percy/config@1.10.4":
|
||||
version "1.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@percy/config/-/config-1.10.4.tgz#8df1d07f718e5ba377cd4acc6da6df5c5933ce2f"
|
||||
integrity sha512-K0p4fKE77jsXWaNJIOP61IbGaA4KHbGXuqchHrFAsxh8HsdzadntFsTkXxtyS6eu6v4kfeLo0j25Mq6xkgQ5gQ==
|
||||
dependencies:
|
||||
"@percy/env" "1.8.1"
|
||||
"@percy/logger" "1.8.1"
|
||||
"@percy/logger" "1.10.4"
|
||||
ajv "^8.6.2"
|
||||
cosmiconfig "^7.0.0"
|
||||
yaml "^2.0.0"
|
||||
|
||||
"@percy/config@1.2.0":
|
||||
version "1.2.0"
|
||||
@@ -5444,16 +5454,6 @@
|
||||
cosmiconfig "^7.0.0"
|
||||
yaml "^2.0.0"
|
||||
|
||||
"@percy/config@1.8.1":
|
||||
version "1.8.1"
|
||||
resolved "https://registry.yarnpkg.com/@percy/config/-/config-1.8.1.tgz#46d73b8cdb0e1d7400e8d91fe12e9f6ea08d2b31"
|
||||
integrity sha512-yKdKx0kh5xyVxBdNVExXsoNuSmKcmpma31DkqqacDUu2nYSjuCGxr3j3y8BRAKURfj59fdhwpFNmjVVB1xiVWA==
|
||||
dependencies:
|
||||
"@percy/logger" "1.8.1"
|
||||
ajv "^8.6.2"
|
||||
cosmiconfig "^7.0.0"
|
||||
yaml "^2.0.0"
|
||||
|
||||
"@percy/core@1.2.0":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@percy/core/-/core-1.2.0.tgz#aee388447faf3dac0f829d450cb2db24b7fa5f47"
|
||||
@@ -5474,14 +5474,14 @@
|
||||
ws "^8.0.0"
|
||||
|
||||
"@percy/core@^1.0.0-beta.48":
|
||||
version "1.8.1"
|
||||
resolved "https://registry.yarnpkg.com/@percy/core/-/core-1.8.1.tgz#b1e419da98251b370cdcea436bb702ee3461d203"
|
||||
integrity sha512-wwTSJWoKK8tr8AbORlJGJ7uz55v8oUdOrfZtCnRPssWiceaWFXecRbjLXcNCCz0/2nT6Y1ilDsEOjlExYnKhww==
|
||||
version "1.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@percy/core/-/core-1.10.4.tgz#65fd447e19f2cb870880ab97575bbcb4012b9d50"
|
||||
integrity sha512-7Fu9h6XjMNjJF0RDft0GQ6A3uo1SQip+x8yp1oTF3K4qoKywc28EnfPyGeQ83Jju40cu1z6VzjnvnyIWK3/B6Q==
|
||||
dependencies:
|
||||
"@percy/client" "1.8.1"
|
||||
"@percy/config" "1.8.1"
|
||||
"@percy/dom" "1.8.1"
|
||||
"@percy/logger" "1.8.1"
|
||||
"@percy/client" "1.10.4"
|
||||
"@percy/config" "1.10.4"
|
||||
"@percy/dom" "1.10.4"
|
||||
"@percy/logger" "1.10.4"
|
||||
content-disposition "^0.5.4"
|
||||
cross-spawn "^7.0.3"
|
||||
extract-zip "^2.0.1"
|
||||
@@ -5492,43 +5492,43 @@
|
||||
rimraf "^3.0.2"
|
||||
ws "^8.0.0"
|
||||
|
||||
"@percy/cypress@^3.1.0", "@percy/cypress@^3.1.1":
|
||||
"@percy/cypress@^3.1.0":
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@percy/cypress/-/cypress-3.1.1.tgz#4e7c5bdeccf1240b2150fc9d608df72c2f213d4b"
|
||||
integrity sha512-khvWmCOJW7pxwDZPB5ovvbSe11FfNtH8Iyq8PHRYLD9ibAkiAWHZVs07bLK5wju1Q9X8s7zg5uj2yWxIlB1yjA==
|
||||
dependencies:
|
||||
"@percy/sdk-utils" "^1.0.0-beta.44"
|
||||
|
||||
"@percy/dom@1.10.4":
|
||||
version "1.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@percy/dom/-/dom-1.10.4.tgz#c8c6227d6e074547e309da0563fb485ca5d2fb3a"
|
||||
integrity sha512-EevExMWUKvBFe2UvXuskJCoj8Xc28PeX60ktSRvc7Z68wSQZmE2hlu8mfnkQ6KSDyO96duBPrKWJn9EeYFvIWg==
|
||||
|
||||
"@percy/dom@1.2.0":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@percy/dom/-/dom-1.2.0.tgz#c59aae392539cc493145daa928c8d43cfbfdd819"
|
||||
integrity sha512-OThOEuEyczxToc/+Df/aHDFY0O5balTG1w0k91wyZCNEIjD2nhwiAj09m28SmybNpq6TC6j0qnuPTD9rk2vgDw==
|
||||
|
||||
"@percy/dom@1.8.1":
|
||||
version "1.8.1"
|
||||
resolved "https://registry.yarnpkg.com/@percy/dom/-/dom-1.8.1.tgz#b3daa0f6f8d95a5b72df4edfdca615ed04f14f93"
|
||||
integrity sha512-h9XJV+VcVHrMkfIgJ6sJLujtYLzkvRy3aBvUY/iS7yh88qM16pSuTgEHG9fzbOp8ZNZpu6zZdxy4QmeACqzGzw==
|
||||
"@percy/env@1.10.4":
|
||||
version "1.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@percy/env/-/env-1.10.4.tgz#1ba30add5920703e44314d680d469671390d8acd"
|
||||
integrity sha512-11xPV2/yNga+2RZnTkleIdcpqqb4WGNUBhdjMds/45YQJXX1ZbtzGi8eU/UPEHYCeY7L6IZlatIyaE50wZg/Jw==
|
||||
|
||||
"@percy/env@1.2.0":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@percy/env/-/env-1.2.0.tgz#22ec45884f2e7c6d962237c9350ab16625e4e196"
|
||||
integrity sha512-+In1gN8ArNMwyFj8tZMEpqI8CAoLeuZpa99DPP4QNqyNW1+mUEzYobqBJ8VrJDBWqCayWtuxiofQO+ihReBo0Q==
|
||||
|
||||
"@percy/env@1.8.1":
|
||||
version "1.8.1"
|
||||
resolved "https://registry.yarnpkg.com/@percy/env/-/env-1.8.1.tgz#338d87479dc48fc2ca3e0a66c98f0b5235f322c2"
|
||||
integrity sha512-noxlV3fesivvXxnWEODUzdoToIurOolvwlEk+ETmpB933zKTpo55UFD5leV5LWP5Oxwrv4uen2i7ZdHRXPD47Q==
|
||||
"@percy/logger@1.10.4", "@percy/logger@^1.0.0-beta.48":
|
||||
version "1.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@percy/logger/-/logger-1.10.4.tgz#a95532c558bc6ea73c0dd99778c1963871733369"
|
||||
integrity sha512-8rUE5hhwIRoPAdA3Osh4+dkVbXE6q4Pn7xyt63NLoFHt9JR2H/iFowsaetkCCHa6VKKfGMjXm04hmrP2o0vUWw==
|
||||
|
||||
"@percy/logger@1.2.0":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@percy/logger/-/logger-1.2.0.tgz#4739e57df77db1377a67be1d2a34575a68718f4a"
|
||||
integrity sha512-UfCJA2jRBwBqGdCNKlNK2Y5QYf0h5dsI56GdYO97hCv1GOj29X+1xQsfYFTbocTR5EmoBsS41sErBZ1aVBtDng==
|
||||
|
||||
"@percy/logger@1.8.1", "@percy/logger@^1.0.0-beta.48":
|
||||
version "1.8.1"
|
||||
resolved "https://registry.yarnpkg.com/@percy/logger/-/logger-1.8.1.tgz#91e1fb3ec2952dfd170201ab101aa1a7f505c778"
|
||||
integrity sha512-O1GpuuN6pzBk/dso57LS90APbRNfc4y0qsGEIph+8f1zK6dBZmalwKLzhgrvb267rLe3pduYM5fCiYel0pqh7Q==
|
||||
|
||||
"@percy/sdk-utils@^1.0.0-beta.44":
|
||||
version "1.0.0-beta.48"
|
||||
resolved "https://registry.yarnpkg.com/@percy/sdk-utils/-/sdk-utils-1.0.0-beta.48.tgz#47e59d92c7df19fe13faf5458702fd2b9a0e0b76"
|
||||
@@ -5582,13 +5582,6 @@
|
||||
tslib "^2.0.0"
|
||||
warning "^4.0.3"
|
||||
|
||||
"@reach/visually-hidden@0.10.4":
|
||||
version "0.10.4"
|
||||
resolved "https://registry.yarnpkg.com/@reach/visually-hidden/-/visually-hidden-0.10.4.tgz#ab390db0adf759393af4d856f84375468b1df676"
|
||||
integrity sha512-GnuPuTRCf+Ih47BoKvGyB+jP8EVWLb04GfbGa5neOrjdp90qrb4zr7pMSL4ZvTsrxt9MRooJA2BhSxs5DbyqCQ==
|
||||
dependencies:
|
||||
tslib "^2.0.0"
|
||||
|
||||
"@rollup/plugin-commonjs@^17.1.0":
|
||||
version "17.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-17.1.0.tgz#757ec88737dffa8aa913eb392fade2e45aef2a2d"
|
||||
@@ -10859,8 +10852,8 @@ brorand@^1.0.1, brorand@^1.1.0:
|
||||
integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=
|
||||
|
||||
"browser-logos@github:alrra/browser-logos":
|
||||
version "69.0.4"
|
||||
resolved "https://codeload.github.com/alrra/browser-logos/tar.gz/90fdf03c58819fd31892869712feb7d614d79a96"
|
||||
version "72.0.0"
|
||||
resolved "https://codeload.github.com/alrra/browser-logos/tar.gz/6e3e6a8da0dc8ec9851a6987fd9bd3523fe1876c"
|
||||
|
||||
browser-process-hrtime@^1.0.0:
|
||||
version "1.0.0"
|
||||
@@ -23830,13 +23823,6 @@ mobx-react-lite@^1.4.2:
|
||||
resolved "https://registry.yarnpkg.com/mobx-react-lite/-/mobx-react-lite-1.5.2.tgz#c4395b0568b9cb16f07669d8869cc4efa1b8656d"
|
||||
integrity sha512-PyZmARqqWtpuQaAoHF5pKX7h6TKNLwq6vtovm4zZvG6sEbMRHHSqioGXSeQbpRmG8Kw8uln3q/W1yMO5IfL5Sg==
|
||||
|
||||
mobx-react@6.1.7:
|
||||
version "6.1.7"
|
||||
resolved "https://registry.yarnpkg.com/mobx-react/-/mobx-react-6.1.7.tgz#2fe620851ef33df38e50645101321830a07fc4e2"
|
||||
integrity sha512-TXwqweY7yEbMl+0F5jOO5bHWUbgeNJr8o1or+1NdhWWg6duIqsGW1D6ojNmn2RO27vRJHkZrp4kjv6919nHS0A==
|
||||
dependencies:
|
||||
mobx-react-lite "^1.4.2"
|
||||
|
||||
mobx-react@6.1.8:
|
||||
version "6.1.8"
|
||||
resolved "https://registry.yarnpkg.com/mobx-react/-/mobx-react-6.1.8.tgz#5b9a3950463d58c154dda2c94d16d48ed8fcb02e"
|
||||
|
||||
Reference in New Issue
Block a user