chore: Intregrate runner packages. (#23028)

* chore: Intregrate runner packages.

* Remove unnecessary Studio react files.

* Remove unnecessary gif

* runner-shared to runner-ct.

* fix path.

* fix package.json

* Remove scss files from runner-ct

* Remove runner-ct

* Remove runner-shared and runner-ct comments.

* Feedback

* chore: reduce parallelism for reporter-componen-tests

* chore: reduce paralelleism

Co-authored-by: Emily Rohrbough <emilyrohrbough@users.noreply.github.com>
Co-authored-by: Lachlan Miller <lachlan.miller.1990@outlook.com>
This commit is contained in:
Kukhyeon Heo
2022-08-11 13:07:10 +09:00
committed by GitHub
parent 26886c4ce4
commit 2d119ad46a
107 changed files with 76 additions and 3416 deletions

2
.github/CODEOWNERS vendored
View File

@@ -40,8 +40,6 @@
/packages/rewriter/ @cypress-io/end-to-end
/packages/root/ @cypress-io/end-to-end
/packages/runner/ @cypress-io/end-to-end
/packages/runner-ct/ @cypress-io/component-testing
/packages/runner-shared/ @cypress-io/end-to-end
/packages/server/ @cypress-io/end-to-end
/packages/socket/ @cypress-io/end-to-end
/packages/static/ @cypress-io/end-to-end

3
.gitignore vendored
View File

@@ -78,9 +78,6 @@ system-tests/lib/fixtureDirs.ts
# from npm/webpack-dev-server
/npm/webpack-dev-server/cypress/videos
# from runner-ct
/packages/runner-ct/cypress/screenshots
# from errors
/packages/errors/__snapshot-images__
/packages/errors/__snapshot-md__

View File

@@ -83,13 +83,6 @@
"cwd": "[cwd]/packages/runner",
"command": "yarn watch"
},
{
"name": "packages/runner-ct watch",
"focus": true,
"onlySingle": true,
"cwd": "[cwd]/packages/runner-ct",
"command": "yarn watch"
},
{
"name": "packages/driver cypress open",
"focus": true,

View File

@@ -271,8 +271,6 @@ Here is a list of the core packages in this repository with a short description,
| [reporter](./packages/reporter) | `@packages/reporter` | The reporter shows the running results of the tests (The Command Log UI). |
| [root](./packages/root) | `@packages/root` | Dummy package pointing at the root of the repository. |
| [runner](./packages/runner) | `@packages/runner` | The runner is the minimal "chrome" around the user's application under test. |
| [runner-ct](./packages/runner-ct) | `@packages/runner-ct` | The runner for component testing |
| [runner-shared](./packages/runner-shared) | `@packages/runner-shared` | The shared components between the `runner` and the `runner-ct` packages |
| [server](./packages/server) | `@packages/server` | The <3 of Cypress. This orchestrates everything. The backend node process. |
| [server-ct](./packages/server-ct) | `@packages/server-ct` | Some Component Testing specific overrides. Mostly extends functionality from `@packages/server` |
| [socket](./packages/socket) | `@packages/socket` | A wrapper around socket.io to provide common libraries. |

View File

@@ -1607,7 +1607,7 @@ jobs:
percy:
type: boolean
default: false
parallelism: 7
parallelism: 2
steps:
- run-new-ui-tests:
browser: chrome

View File

@@ -91,13 +91,13 @@ The terminology can get a bit confusing as Vue Router's `params` are not the que
## Using existing, Vite-incompatible modules
Some of our modules, like `@packages/reporter`, `@packages/driver` and `@packages/runner-shared` cannot be easily
Some of our modules, like `@packages/reporter`, `@packages/driver` and `@packages/runner` cannot be easily
used with Vite due to circular dependencies and modules that do not have compatible ESM builds.
To work around this, when consuming existing code, it is bundled with webpack and made available under the
`window.UnifiedRunner` namespace. It is injected via [`injectBundle`](./src/runner/injectBundle.ts).
To add more code to the bundle, add it in the bundle root, `@packages/runner-ct/src/main.tsx` and attach it to
To add more code to the bundle, add it in the bundle root, `@packages/runner/src/main.tsx` and attach it to
`window.UnifiedRunner`.
As a rule of thumb, avoid importing from the older, webpack based modules into this package. Instead, if you want to consume code from those older, webpack bundled modules, you should add them to the webpack root and consume them via `window.UnifiedRunner`. Ideally, update [`index.d.ts`](./index.d.ts) to add the types, as well.

View File

@@ -51,11 +51,11 @@ declare global {
/**
* Any React components or general code needed from
* runner-shared, reporter or driver are also bundled with
* runner, reporter or driver are also bundled with
* webpack and made available via the window.UnifedRunner namespace.
*
* We cannot import the correct types, because this causes the linter and type
* checker to run on runner-shared and reporter, and it blows up.
* checker to run on runner and reporter, and it blows up.
*/
Reporter: any
shortcuts: {

View File

@@ -8,7 +8,7 @@
* - reporter
* which are built with React and bundle with webpack.
*
* The entry point for the webpack bundle is `runner-ct/main.tsx`.
* The entry point for the webpack bundle is `runner/main.tsx`.
* Any time you need to consume some existing code, add it to the `window.UnifiedRunner`
* namespace there, and access it with `window.UnifiedRunner`.
*

View File

@@ -22,7 +22,6 @@
"@packages/network": "0.0.0-development",
"@packages/rewriter": "0.0.0-development",
"@packages/runner": "0.0.0-development",
"@packages/runner-shared": "0.0.0-development",
"@packages/server": "0.0.0-development",
"@packages/socket": "0.0.0-development",
"@packages/ts": "0.0.0-development",

View File

@@ -1,5 +1,5 @@
import $ from 'jquery'
import $dimensions from '@packages/runner-shared/src/dimensions'
import $dimensions from '@packages/runner/src/dom/dimensions'
const resetStyles = `
border: none !important;

View File

@@ -2,7 +2,7 @@ import path from 'path'
let fs: typeof import('fs-extra')
export type RunnerPkg = 'app' | 'runner' | 'runner-ct'
export type RunnerPkg = 'app' | 'runner'
type FoldersWithDist = 'static' | 'driver' | RunnerPkg | 'launchpad'

View File

@@ -1,137 +0,0 @@
{
"plugins": [
"cypress",
"@cypress/dev"
],
"extends": [
"plugin:@cypress/dev/general",
"plugin:@cypress/dev/tests",
"plugin:@cypress/dev/react",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"../reporter/src/.eslintrc.json"
],
"parser": "@typescript-eslint/parser",
"env": {
"cypress/globals": true
},
"rules": {
"react/display-name": "off",
"react/function-component-definition": [
"error",
{
"namedComponents": "arrow-function",
"unnamedComponents": "arrow-function"
}
],
"react/jsx-boolean-value": [
"error",
"always"
],
"react/jsx-closing-bracket-location": [
"error",
"line-aligned"
],
"react/jsx-closing-tag-location": "error",
"react/jsx-curly-brace-presence": [
"error",
{
"props": "never",
"children": "never"
}
],
"react/jsx-curly-newline": "error",
"react/jsx-filename-extension": [
"warn",
{
"extensions": [
".js",
".jsx",
".tsx"
]
}
],
"react/jsx-first-prop-new-line": "error",
"react/jsx-max-props-per-line": [
"error",
{
"maximum": 1,
"when": "multiline"
}
],
"react/jsx-no-bind": [
"error",
{
"ignoreDOMComponents": true
}
],
"react/jsx-no-useless-fragment": "error",
"react/jsx-one-expression-per-line": [
"error",
{
"allow": "literal"
}
],
"react/jsx-sort-props": [
"error",
{
"callbacksLast": true,
"ignoreCase": true,
"noSortAlphabetically": true,
"reservedFirst": true
}
],
"react/jsx-tag-spacing": [
"error",
{
"closingSlash": "never",
"beforeSelfClosing": "always"
}
],
"react/jsx-wrap-multilines": [
"error",
{
"declaration": "parens-new-line",
"assignment": "parens-new-line",
"return": "parens-new-line",
"arrow": "parens-new-line",
"condition": "parens-new-line",
"logical": "parens-new-line",
"prop": "parens-new-line"
}
],
"react/no-array-index-key": "error",
"react/no-unescaped-entities": "off",
"react/prop-types": "off",
"quote-props": [
"error",
"as-needed"
]
},
"overrides": [
{
"files": [
"lib/*"
],
"rules": {
"no-console": 1
}
},
{
"files": [
"**/*.json"
],
"rules": {
"quotes": "off",
"comma-dangle": "off"
}
},
{
"files": "*.tsx",
"rules": {
"no-unused-vars": "off",
"react/jsx-no-bind": "off"
}
}
]
}

View File

@@ -1 +0,0 @@
cypress/videos/*

View File

@@ -1,6 +0,0 @@
# Runner CT
This is an old package, deprecated in favor of `@packages/app`. It has two remaining responsibilities before it can be entirely removed:
1. Bundles `@packages/reporter` and `@packages/driver` via webpack. Once those can be directly imported to `@packages/app`, we can remove this.
2. Bundles styles for `@packages/reporter`, loaded in `main.scss`. Ideally, reporter should import its own styles.

View File

@@ -1,69 +0,0 @@
{
"name": "@packages/runner-ct",
"version": "0.0.0-development",
"private": true,
"browser": "src/index.js",
"scripts": {
"build": "node ../../scripts/run-webpack",
"build-prod": "cross-env NODE_ENV=production yarn build && tsc",
"clean-deps": "rimraf node_modules",
"cypress:open": "ts-node ../../scripts/cypress.js open --component --project .",
"cypress:run": "ts-node ../../scripts/cypress.js run --component --project .",
"postinstall": "echo '@packages/runner needs: yarn build'",
"lint": "eslint --ext .js,.jsx,.ts,.tsx,.json src",
"test": "ts-node ../../scripts/cypress.js run --component --project .",
"watch": "node ../../scripts/run-webpack --watch --progress --config webpack.config.ts"
},
"dependencies": {},
"devDependencies": {
"@babel/core": "^7.12.3",
"@babel/preset-env": "^7.12.1",
"@cypress/react-tooltip": "0.5.3",
"@fortawesome/free-regular-svg-icons": "5.15.2",
"@fortawesome/react-fontawesome": "^0.1.17",
"@packages/driver": "0.0.0-development",
"@packages/icons": "0.0.0-development",
"@types/http-proxy": "1.17.4",
"@types/node": "14.14.31",
"@types/sockjs-client": "1.1.0",
"babel-loader": "8.1.0",
"bluebird": "3.5.3",
"cash-dom": "^8.1.0",
"chai": "^4.2.0",
"classnames": "2.3.1",
"clean-webpack-plugin": "^3.0.0",
"cypress-real-events": "1.6.0",
"eslint-plugin-mocha": "^8.0.0",
"eslint-plugin-react": "^7.22.0",
"eslint-plugin-react-hooks": "^4.2.0",
"express": "^4.17.1",
"fuzzysort": "^1.1.4",
"hotkeys-js": "3.8.2",
"html-webpack-plugin": "^4.5.0",
"koa": "^2.13.0",
"mobx": "5.15.4",
"mobx-react": "6.1.8",
"mocha": "^8.1.3",
"nanoid": "3.1.31",
"react": "16.8.6",
"react-devtools-inline": "^4.10.1",
"react-dom": "16.8.6",
"react-split-pane": "^0.1.92",
"rimraf": "3.0.2",
"sass": "1.44.0",
"sass-loader": "^10.0.3",
"sockjs-client": "^1.5.0",
"strip-ansi": "6.0.0",
"ts-loader": "^8.0.5",
"ts-node": "^10.2.1",
"watch": "^1.0.2",
"webpack": "^4.44.2"
},
"peerDependencies": {
"webpack": "^4.0.0 || ^5.0.0",
"webpack-dev-middleware": "*"
},
"files": [
"dist"
]
}

View File

@@ -1,36 +0,0 @@
@use '../../variables.scss' as *;
.specs-list-search-input-container {
display: flex;
justify-content: flex-start;
align-items: center;
position: sticky;
top: 0;
width: 100%;
padding: 8px;
box-sizing: border-box;
background-color: white;
box-shadow: $shadow-xs;
z-index: 1;
input {
width: 100%;
font-size: 18px;
height: 32px;
color: #848484;
border-radius: 6px;
border: 1px solid #E8E8EC;
padding: 0 8px 0 16px;
&::placeholder {
color: #B4B5BC;
}
// avoid default focus outline because of input border radius
&:focus {
outline: none;
box-shadow: 0px 0px 2px #0012ff;
}
}
}

View File

@@ -1,43 +0,0 @@
.keyboard-helper-container {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
background-color: white;
.keyboard-helper {
padding: 8px 32px;
color: #555;
// background: white;
font-family: "Mulish", "Helvetica Neue", "Arial", sans-serif;
font-size: 13px;
width: 224px;
.keyboard-shortcut {
display: flex;
margin-top: 8px;
height: 23px;
justify-content: space-between;
.shortcut {
display: flex;
.key {
display: flex;
font-family: sans-serif; // display keys symbols correctly
justify-content: center;
align-items: center;
border: 1px solid rgba(255, 255, 255, 0.4);
height: 23px;
min-width: 23px;
margin-right: 4px;
padding: 0px 4px;
font-size: 0.8125rem;
border-radius: 4px;
pointer-events: none;
background-color: #ddd;
}
}
}
}
}

View File

@@ -1,7 +0,0 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
}
export const cssExports: CssExports;
export default cssExports;

View File

@@ -1,36 +0,0 @@
.no-spec {
display: flex;
justify-content: space-around;
align-items: center;
height: 100%;
flex-direction: column;
color: #555;
background: white;
font-family: "Mulish", "Helvetica Neue", "Arial", sans-serif;
font-size: 13px;
.no-spec-content-container {
display: flex;
flex-basis: 45%;
flex-direction: column;
align-items: center;
a {
color: #3386D4;
cursor: pointer;
&:hover {
text-decoration: underline;
}
}
.no-spec-title {
margin-top: 16px;
margin-bottom: 8px;
}
.no-spec-custom-children {
margin-top: 32px;
}
}
}

View File

@@ -1,7 +0,0 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
}
export const cssExports: CssExports;
export default cssExports;

View File

@@ -1,5 +0,0 @@
@use '../variables' as *;
.ctReporterHeader {
min-height: $runner-ct-header-height;
}

View File

@@ -1,8 +0,0 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'ctReporterHeader': string;
'display-none': string;
}
export const cssExports: CssExports;
export default cssExports;

View File

@@ -1,134 +0,0 @@
@use '../variables' as *;
$box-shadow-closest: 0px 0px 5px rgba(0, 0, 0, 0.4);
.app {
display: flex;
background: white;
}
.appWrapper {
position: relative;
height: 100vh;
width: 100%;
}
.appWrapperScreenshotting {
margin-inline: 0;
}
.runnerCt {
left: 0;
header {
position: static;
top: unset;
left: unset;
right: unset;
bottom: unset;
min-height: $runner-ct-header-height;
}
.size-container {
transform-origin: 0 0;
}
}
.noSpecAut {
background: white;
}
.screenshotting {
box-shadow: none;
}
.leftNav {
background: $left-nav-background-color;
z-index: 4;
border-right: 1px solid $border-color;
height: 100vh;
}
.runner {
box-shadow: shadow(s);
left: 0 !important;
}
.reporter {
box-shadow: shadow(l);
background: $reporter-background-color;
// border-right: 1px solid $border-color;
z-index: 2;
}
.ctPlugins {
height: 100%;
width: 100%;
.ctPluginsHeader {
height: 40px; // make sure this is hardcoded in as well RunnerCt.tsx
display: flex;
border-top: 1px solid $metal-20;
.ctTogglePluginsSectionButton {
margin-left: auto;
margin-right: 4px;
border: none;
background-color: transparent;
transition: transform .3s ease-in-out;
&.ctTogglePluginsSectionButtonOpen {
will-change: transform;
transform: rotate(180deg);
}
}
.ctPluginToggleButton {
font-family: $font-stack-sans;
cursor: pointer;
height: 100%;
width: 100%;
border: none;
background-color: transparent;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 16px;
transition: border-bottom-color .3s ease-in-out;
:focus {
outline: none;
}
.ctPluginsName {
padding: 2px 4px;
border-bottom: 2px solid transparent;
&:hover {
border-bottom: 2px solid $chill-40;
}
}
}
}
.ctDevtoolsContainer {
height: 100%;
width: 100%;
}
}
.largerIcon {
font-size: 1.75rem !important;
}
.noSpecsDescription {
text-align: center;
margin: 0 1rem;
line-height: 1.5;
.folder {
border-radius: 4px;
padding: 1px 4px;
background-color: #ddd;
}
}

View File

@@ -1,27 +0,0 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'app': string;
'appWrapper': string;
'appWrapperScreenshotting': string;
'ctDevtoolsContainer': string;
'ctPluginToggleButton': string;
'ctPlugins': string;
'ctPluginsHeader': string;
'ctPluginsName': string;
'ctTogglePluginsSectionButton': string;
'ctTogglePluginsSectionButtonOpen': string;
'display-none': string;
'folder': string;
'largerIcon': string;
'leftNav': string;
'noSpecAut': string;
'noSpecsDescription': string;
'reporter': string;
'runner': string;
'runnerCt': string;
'screenshotting': string;
'size-container': string;
}
export const cssExports: CssExports;
export default cssExports;

View File

@@ -1,102 +0,0 @@
@use "../variables.scss" as *;
@import "../runner-ct-variables.scss";
@import "../../../reporter/src/lib/variables.scss";
/**
* Styles that cannot be transformed by scoped modules should live here. Examples are:
* - override Runner globals (in a pinch)
* - publicly interface with 3rd party libs (Resizer)
*/
body, html {
font-size: 1rem !important;
font-family: $font-stack-sans;
font-size: text(m);
* :focus {
outline-offset: 1px;
outline-width: 1px;
outline-color: $chill-20;
outline-style: auto;
}
}
.reporter {
.runnable-header {
box-shadow: shadow(m);
}
}
.runner {
// @include checkerboard();
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1IiBoZWlnaHQ9IjUiPgo8cmVjdCB3aWR0aD0iNSIgaGVpZ2h0PSI1IiBmaWxsPSIjZGJkYmRiIj48L3JlY3Q+CjxwYXRoIGQ9Ik0wIDVMNSAwWk02IDRMNCA2Wk0tMSAxTDEgLTFaIiBzdHJva2U9IiNjNGM0YzQiIHN0cm9rZS13aWR0aD0iMSI+PC9wYXRoPgo8L3N2Zz4=");
}
.aut-iframe-screenshotting {
height: min(100vh, 100%) !important;
overflow: scroll !important;
}
// Prevent left-most Resizer from showing up when the pane is hidden.
.isSpecsListClosed {
> .Resizer {
display: none;
}
}
// Must be globally scoped. Bummer.
$resizerLineSize: 4px;
.Resizer {
$resize-thickness: 12px;
background: none;
transition: background-color 200ms ease-in-out;
z-index: 10;
box-sizing: border-box;
background-clip: padding-box;
&:after {
content: '';
position: relative;
display: block;
background: transparent;
transition: background 200ms ease;
position: fixed;
}
&:hover {
&:after {
background: $chill-30;
}
}
&.horizontal {
margin: -($resize-thickness * 0.5) 0;
height: $resize-thickness;
width: 100%;
cursor: row-resize;
border-top: 5px solid rgba(255, 255, 255, 0);
border-bottom: 5px solid rgba(255, 255, 255, 0);
&:after {
height: $resizerLineSize;
width: 100%;
}
}
&.vertical {
margin: 0 -($resize-thickness * 0.5);
width: $resize-thickness;
height: 100%;
cursor: col-resize;
border-left: 5px solid rgba(255, 255, 255, 0);
border-right: 5px solid rgba(255, 255, 255, 0);
&:after {
width: $resizerLineSize;
height: 100%;
}
}
&.disabled {
display: none;
}
}

View File

@@ -1,7 +0,0 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
}
export const cssExports: CssExports;
export default cssExports;

View File

@@ -1,20 +0,0 @@
@use '../variables.scss' as *;
.iframes-ct-container {
margin: 0 8px;
padding: 16px 0;
display: flex;
justify-content: center;
align-items: center;
}
.iframes-ct-container-screenshotting {
margin: 0;
padding: 0;
}
.size-container {
overflow: auto;
box-shadow: shadow(m);
max-width: 100%;
}

View File

@@ -1,7 +0,0 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
}
export const cssExports: CssExports;
export default cssExports;

View File

@@ -1,3 +0,0 @@
import '@packages/runner/src/main.scss'
import './main'

View File

@@ -1,3 +0,0 @@
.logo {
max-width: 100%;
}

View File

@@ -1,76 +0,0 @@
@use 'baseColors' as *;
@use 'semanticColors' as *;
@use 'typography' as *;
$left-nav-width: 48px;
$icon-color: $metal-20;
$active-color: $brand-01;
.leftNav {
display: grid;
grid-template-columns: $left-nav-width;
grid-template-rows: auto auto;
width: $left-nav-width;
margin: 0;
row-gap: 0.5rem;
padding: 0;
}
.top, .bottom {
display: grid;
list-style-type: none;
row-gap: 0.5rem;
grid-template-rows: repeat(auto-fit, 48px)
}
.top {
padding-top: 1.5rem;
}
.bottom {
display: grid;
align-content: flex-end;
padding-bottom: 2rem;
}
.item {
height: 100%;
font-size: text(ml);
cursor: pointer;
color: $icon-color;
&:before {
content: '';
width: 4px;
position: absolute;
height: $left-nav-width;
display: block;
background: transparent;
}
}
.active {
color: $active-color;
&:before {
background: $brand-01;
}
}
.inactive {
:hover {
color: $active-color;
}
}
.itemAnchor {
text-decoration: none;
}
.icon {
display: block;
margin: auto;
height: 100%;
}

View File

@@ -1,54 +0,0 @@
@use 'spacing' as *;
@use 'semanticColors' as *;
@use 'css-util' as *;
.group {
display: flex;
flex-direction: column;
overflow: hidden;
}
.header {
width: 100%;
cursor: pointer;
@include no-selection;
&:hover {
background-color: $button-white-hover-color;
}
&:active {
background-color: $button-white-push-color;
}
}
.disabled {
color: grey;
.title {
cursor: unset;
&::before {
content: '';
}
}
}
.title {
display: inline-block;
}
.content {
// TODO: Add transition
height: 0;
}
.expanded {
.content {
flex-grow: 1;
height: 100%;
}
}

View File

@@ -1,72 +0,0 @@
@use 'semanticColors' as *;
@use 'spacing' as *;
@use 'typography' as *;
@use 'css-util' as *;
.tree {
> div {
// Container div for nodes
padding-bottom: spacing(l);
}
}
.node {
display: grid;
grid-template-columns: spacing(m) 1fr;
column-gap: spacing(xs);
align-items: center;
background: repeating-linear-gradient(90deg, $control-slight-color, $control-slight-color 1px, transparent 1px, transparent spacing(m), );
background-repeat: no-repeat;
background-size: 0 100%;
// Start background at 1/2 indent spacing (m = 1rem)
background-position-x: spacing(s);
@include text(ms);
:global(.svg-inline--fa) {
bottom: 0;
}
> :first-child {
justify-self: center;
}
}
.file {
cursor: pointer;
@include no-selection;
&:hover {
background-color: $button-white-hover-color;
}
&:active {
background-color: $button-white-push-color;
}
}
.active {
color: $control-text-color-white;
background: none;
background-color: $button-blue-color;
&:hover {
background-color: $button-blue-color;
}
&:active {
background-color: $button-blue-hover-color;
}
}
.highlight {
> span {
font-weight: $highlight-weight;
}
}
.placeholder {
text-align: center;
}

View File

@@ -1,23 +0,0 @@
@use 'surfaces' as *;
.focusWrapper {
&:focus {
outline: none;
}
}
.child {
display: grid;
grid-template-rows: 1fr;
height: 100%;
}
.focus {
@include focused;
&::after {
// TODO: Improve this
border-radius: 0;
// border-width: 1px;
}
}

View File

@@ -1,69 +0,0 @@
@use 'semanticColors' as *;
@use 'typography' as *;
@use 'spacing' as *;
@use 'surfaces' as *;
@use 'func' as *;
@use 'css-util' as util;
$button-vertical-padding: change-rem-unit-to-em(spacing(xs));
$button-horizontal-padding: change-rem-unit-to-em(spacing(s));
.button {
position: relative;
display: inline-block;
// Reset
@include util.no-selection;
border: 0;
text-decoration: none;
cursor: pointer;
// Style
padding: $button-vertical-padding $button-horizontal-padding;
border-radius: $button-radius;
color: $control-text-color-white;
background-color: $button-blue-color;
&:hover {
background-color: $button-blue-hover-color;
}
&:active {
background-color: $button-blue-push-color;
}
&:focus {
outline: none;
}
&.white {
color: $control-text-color-black;
background-color: $button-white-color;
border: 1px solid $control-border-color;
&:hover {
background-color: $button-white-hover-color;
}
&:active {
background-color: $button-white-push-color;
}
}
&.disableBorder {
border: 0;
}
}
:global {
:local(.button.white:not(.disableBorder)) {
&.focused::after {
// White buttons have a border that needs to be compensated for
top: -1px;
left: -1px;
right: -1px;
bottom: -1px;
}
}
}

View File

@@ -1,27 +0,0 @@
$icon-margin: 0.15em;
$icon-bottom-offset: 0.125em;
$icon-size: 1em - $icon-margin * 2;
:global(.svg-inline--fa) {
// TODO: Is there ever a need for the icon to not take a square space as long as it's properly centered?
&.icon {
position: relative;
width: $icon-size;
height: $icon-size;
bottom: $icon-bottom-offset;
}
&.ignoreTextCenter {
width: 1em;
height: 1em;
bottom: auto;
}
&.sizeWithoutCenter {
bottom: auto;
}
}

View File

@@ -1,9 +0,0 @@
.icon {
background-color: orange;
border: 1px solid black;
}
.textIcon {
border: 1px solid black;
}

View File

@@ -1,100 +0,0 @@
@use 'spacing' as *;
@use 'semanticColors' as *;
@use '../icon/Icon.module.scss' as *;
@use 'surfaces' as *;
$icon-overall-size: 1.5em;
$input-icon-margin: 0.25em;
.iconInput {
position: relative;
display: flex;
align-items: center;
// No actual border drawn. This provides the mask for the rounded corners to clip child elements
border-radius: $button-radius;
overflow: hidden;
z-index: 0;
&::after {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border: 1px solid $control-border-color;
border-radius: $button-radius;
pointer-events: none;
}
.wrapper {
display: flex;
flex-grow: 1;
&:first-child {
// If first child, apply border padding
padding-left: spacing(s);
}
&:last-child {
// If last child, apply border padding
padding-right: spacing(s);
}
}
.input {
flex-grow: 1;
// Required to allow input to shrink in certain size scenarios
width: 0;
padding: 0;
background-color: transparent;
border: 0;
border-radius: 0;
&:focus {
outline: none;
}
}
.icon {
flex-grow: 0;
flex-shrink: 0;
// Icon
margin: 0 $input-icon-margin;
bottom: 0;
color: $control-text-color-black;
}
.iconButton {
// See global expression below
// Make sure button fills entire height, to enable the button focus ring to cover the IconInput border
align-self: stretch;
padding: 0 $input-icon-margin;
line-height: 1;
border-radius: 0;
&::after {
z-index: 1;
}
}
}
:global {
:local(.iconButton) {
&.focused {
// Set overflow and border radius to clip corners when focused
overflow: hidden;
border-radius: $button-radius;
}
}
}

View File

@@ -1,20 +0,0 @@
@use 'semanticColors' as *;
@use 'surfaces' as *;
@use 'spacing' as *;
input.input {
padding: 0 spacing(s);
font-weight: normal;
border: 1px solid $control-border-color;
border-radius: $button-radius;
}
/**
* Wrapper for standalone inputs to allow for a proper focus ring
*/
.wrapper {
display: inline-block;
position: relative;
}

View File

@@ -1,5 +0,0 @@
@use 'semanticColors' as *;
.placeholder {
color: $control-text-color-dim;
}

View File

@@ -1,139 +0,0 @@
@import './func.scss';
$colors: (
metal-100: rgba(0, 0, 0, 1), // #000000;
metal-90: rgba(33, 36, 38, 1), // #212426;
metal-80: rgba(45, 49, 52, 1), // #2d3134;
metal-70: rgba(62, 67, 71, 1), // #3e4347;
metal-60: rgba(83, 90, 95, 1), // #535a5f;
metal-50: rgba(107, 116, 123, 1), // #6b747b;
metal-40: rgba(135, 144, 151, 1), // #879097;
metal-30: rgba(160, 167, 172, 1), // #a0a7ac;
metal-20: rgba(190, 194, 198, 1), // #bec2c6;
metal-10: rgba(230, 232, 234, 1), // #e6e8ea;
metal-05: rgba(244, 245, 246, 1), // #f4f5f6;
metal-00: rgba(255, 255, 255, 1), // #ffffff;
red-70: rgba(153, 11, 18, 1), // #990b12;
red-60: rgba(191, 13, 22, 1), // #bf0d16;
red-50: rgba(224, 16, 26, 1), // #e0101a;
red-40: rgba(241, 55, 64, 1), // #f13740;
chill-90: rgba(8, 33, 68, 1), // #082144;
chill-80: rgba(12, 49, 100, 1), // #0c3164;
chill-70: rgba(16, 66, 137, 1), // #104289;
chill-60: rgba(21, 86, 178, 1), // #1556b2;
chill-50: rgba(27, 111, 228, 1), // #1b6fe4;
chill-40: rgba(73, 142, 238, 1), // #498eee;
chill-30: rgba(118, 168, 239, 1), // #76a8ef;
chill-20: rgba(164, 197, 244, 1), // #a4c5f4;
chill-10: rgba(222, 235, 252, 1), // #deebfc;
chill-05: rgba(237, 243, 253, 1), // #edf3fd;
olive-60: rgba(93, 100, 12, 1), // #5d640c;
olive-50: rgba(114, 123, 15, 1), // #727b0f;
olive-40: rgba(143, 154, 25, 1), // #8f9a19;
olive-30: rgba(211, 228, 27, 1), // #d3e41b;
olive-20: rgba(225, 237, 100, 1), // #e1ed64;
olive-10: rgba(238, 245, 168, 1), // #eef5a8;
olive-05: rgba(246, 250, 209, 1), // #f6fad1;
papaya-60: rgba(143, 68, 10, 1), // #8f440a;
papaya-50: rgba(190, 90, 14, 1), // #be5a0e;
papaya-40: rgba(235, 107, 10, 1), // #eb6b0a;
papaya-30: rgba(242, 141, 64, 1), // #f28d40;
papaya-20: rgba(246, 175, 121, 1), // #f6af79;
papaya-10: rgba(252, 229, 212, 1), // #fce5d4;
papaya-05: rgba(253, 241, 231, 1), // #fdf1e7;
green-60: rgba(41, 102, 10, 1), // #29660a;
green-50: rgba(54, 133, 15, 1), // #36850f;
green-40: rgba(68, 164, 20, 1), // #44a414;
green-30: rgba(79, 191, 23, 1), // #4fbf17;
green-20: rgba(107, 219, 51, 1), // #6bdb33;
green-10: rgba(204, 244, 185, 1), // #ccf4b9;
green-05: rgba(236, 251, 228, 1), // #ecfbe4;
cran-50: rgba(228, 28, 95, 1), // #e41c5f;
brand-00: rgba(28, 228, 150, 1), // #1ce496;
// TODO: Rewrite these names
brand-01: rgba(8, 41, 63, 1), // #08293f;
accent-00: rgba(177, 99, 255, 1), // #b163ff;
accent-01: rgba(54, 197, 255, 1), // #36c5ff;
accent-02: rgba(230, 255, 30, 1), // #e6ff1e;
);
// TODO: Is this needed?
// :root {
// @each $name, $color in $colors {
// .text-#{"" + $name} {
// color: $color;
// }
// .bg-#{"" + $name} {
// background-color: $color;
// }
// }
// }
// --- Color Variables
@function color($name: string) {
@return var(--#{"" + $name});
}
// Must be manually written out as SASS does not support dynamic variable creation
// Exposes SASS variables as references to CSS variables
$metal-100: color('metal-100');
$metal-90: color('metal-90');
$metal-80: color('metal-80');
$metal-70: color('metal-70');
$metal-60: color('metal-60');
$metal-50: color('metal-50');
$metal-40: color('metal-40');
$metal-30: color('metal-30');
$metal-20: color('metal-20');
$metal-10: color('metal-10');
$metal-05: color('metal-05');
$metal-00: color('metal-00');
$red-70: color('red-70');
$red-60: color('red-60');
$red-50: color('red-50');
$red-40: color('red-40');
$chill-90: color('chill-90');
$chill-80: color('chill-80');
$chill-70: color('chill-70');
$chill-60: color('chill-60');
$chill-50: color('chill-50');
$chill-40: color('chill-40');
$chill-30: color('chill-30');
$chill-20: color('chill-20');
$chill-10: color('chill-10');
$chill-05: color('chill-05');
$olive-60: color('olive-60');
$olive-50: color('olive-50');
$olive-40: color('olive-40');
$olive-30: color('olive-30');
$olive-20: color('olive-20');
$olive-10: color('olive-10');
$olive-05: color('olive-05');
$papaya-60: color('papaya-60');
$papaya-50: color('papaya-50');
$papaya-40: color('papaya-40');
$papaya-30: color('papaya-30');
$papaya-20: color('papaya-20');
$papaya-10: color('papaya-10');
$papaya-05: color('papaya-05');
$green-60: color('green-60');
$green-50: color('green-50');
$green-40: color('green-40');
$green-30: color('green-30');
$green-20: color('green-20');
$green-10: color('green-10');
$green-05: color('green-05');
$cran-50: color('cran-50');
$brand-00: color('brand-00');
$brand-01: color('brand-01');
$accent-00: color('accent-00');
$accent-01: color('accent-01');
$accent-02: color('accent-02');

View File

@@ -1,9 +0,0 @@
@mixin no-selection {
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Old versions of Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
supported by Chrome, Edge, Opera and Firefox */
}

View File

@@ -1,78 +0,0 @@
@use 'baseColors' as *;
@use 'semanticColors' as *;
@use 'spacing' as *;
@use 'surfaces' as *;
@use 'spacing' as *;
@use 'typography' as *;
// BaseColors
:root {
@each $name, $color in $colors {
--#{"" + $name}: #{$color};
}
}
// SemanticColors
// Write semantic CSS color variables to root
// **NOTE**: Most variables do not need to be exposed as a CSS variable
:root {
// See def in semanticColors.scss
--black-rgb-color: #{extract-rgb('metal-100')};
}
// Spacing
@each $name, $text-def in $spacing {
$suffix: str-replace('' + $name, 'space-', '');
.#{'padding-' + $suffix} {
@include padding($suffix)
}
}
// Surfaces
@each $name, $def in $shadow {
$suffix: str-replace('' + $name, 'shadow-', '');
.#{'depth-' + $suffix} {
@include depth($suffix)
}
}
body {
.focused {
@include focused;
}
}
// Typography
// See typography.scss
:root {
--font-stack-sans: #{$internal-font-stack-sans};
--font-stack-mono: #{$internal-font-stack-mono};
}
@each $name, $text-def in $text {
.#{$name} {
@include text(str-replace($name, 'text-', ''))
}
}
.text-mono-m {
@include text-mono-m;
}
.text-mono-s {
@include text-mono-s;
}
.line-height-normal {
@include line-height-normal;
}
.line-height-condensed {
@include line-height-condensed;
}
.line-height-tight {
@include line-height-tight;
}

View File

@@ -1,8 +0,0 @@
@use '../baseColors' as *;
// Exposes $color, stripped of hyphens, as a JS variable when directly imported
:export {
@each $name, $color in $colors {
#{str-replace("" + $name, '-', '')}: #{$color};
}
}

View File

@@ -1,8 +0,0 @@
@use '../spacing.scss' as *;
// Exposes $spacing, as a JS variable when directly imported
:export {
@each $name, $size in $spacing {
#{$name}: #{$size};
}
}

View File

@@ -1,8 +0,0 @@
@use '../surfaces.scss' as *;
// Exposes $shadow as a JS variable when directly imported
:export {
@each $name, $shadow in $shadow {
#{$name}: #{$shadow};
}
}

View File

@@ -1,18 +0,0 @@
@use '../typography.scss' as *;
@use '../func.scss' as *;
// Exposes $text, as a JS variable when directly imported
// This is the only way for JS to directly receive the exposed `.text-*` classes
:export {
@each $name, $text-def in $text {
#{$name}: text(#{str-replace("" + $name, 'text-', '')})
}
// TODO: Can this be improved?
text-mono-m: text-mono-m;
text-mono-s: text-mono-s;
line-height-normal: line-height-normal;
line-height-condensed: line-height-condensed;
line-height-tight: line-height-tight;
}

View File

@@ -1,24 +0,0 @@
/**
* Replace `$search` with `$replace` in `$string`
* @author Hugo Giraudel
* @param {String} $string - Initial string
* @param {String} $search - Substring to replace
* @param {String} $replace ('') - New value
* @return {String} - Updated string
*/
// Taken from https://gist.github.com/PuddingNL/51866d4b9f1151963fbd973bf1d66116
@use "sass:math";
@function str-replace($string, $search, $replace: '') {
$index: str-index($string, $search);
@if $index {
@return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
}
@return $string;
}
@function change-rem-unit-to-em($number) {
@return math.div($number, 1rem) + 0em;
}

View File

@@ -1,5 +0,0 @@
@forward 'baseColors';
@forward 'semanticColors';
@forward 'surfaces';
@forward 'typography';
@forward 'spacing';

View File

@@ -1,36 +0,0 @@
@use 'baseColors' as *;
@use 'func';
/**
* Extracts RGB color channels from a named color definition
*/
@function extract-rgb($color-name: string) {
$color: map-get($colors, $color-name);
@if $color {
@return red($color), green($color), blue($color);
}
@return null;
}
// Provides raw black as a RGB number tuple for substitution into alpha modifying situations (shadows)
// See exposed variable in export.scss
$black-rgb-color: var(--black-rgb-color);
$control-border-color: $metal-30;
// TODO: Find a better name
$control-slight-color: $metal-10;
$control-focus-color: $chill-40;
$button-blue-color: $chill-50;
$button-blue-hover-color: $chill-60;
$button-blue-push-color: $chill-70;
$button-white-color: $metal-00;
$button-white-hover-color: $metal-05;
$button-white-push-color: $metal-10;
$control-text-color-white: $metal-05;
$control-text-color-dim: $metal-50;
$control-text-color-black: $metal-90;

View File

@@ -1,26 +0,0 @@
@use 'func' as *;
$_base-space: 1rem;
$spacing: (
space-xs: 0.25 * $_base-space, // 4px
space-s: 0.5 * $_base-space, // 8px
space-ms: 0.75 * $_base-space, // 12px
space-m: 1 * $_base-space, // 16px
space-ml: 1.25 * $_base-space, // 20px
space-l: 1.5 * $_base-space, // 24px
space-xl: 2 * $_base-space, // 32px
space-2xl: 2.5 * $_base-space, // 40px
space-3xl: 3 * $_base-space, // 48px
space-4xl: 4 * $_base-space, // 64px
);
@function spacing($name: string) {
@return map-get($spacing, "space-" + $name);
}
@mixin padding($name: string) {
padding: spacing($name);
}

View File

@@ -1,53 +0,0 @@
@use 'semanticColors' as *;
@use 'func' as *;
// --- Shadows
// TODO: Need better semantic names
$shadow: (
shadow-flat: none,
shadow-slight: 0 1px 2px 0 rgba($black-rgb-color, 0.05),
shadow-bordered: (0 1px 3px 0 rgba($black-rgb-color, 0.1), 0 1px 2px 0 rgba($black-rgb-color, 0.06)),
shadow-3: (0 4px 6px -1px rgba($black-rgb-color, 0.1), 0 2px 4px -1px rgba($black-rgb-color, 0.06)),
shadow-4: (0 10px 15px -3px rgba($black-rgb-color, 0.1), 0 4px 6px -2px rgba($black-rgb-color, 0.05)),
shadow-popup: (0 20px 25px -5px rgba($black-rgb-color, 0.1), 0 10px 10px -5px rgba($black-rgb-color, 0.04)),
shadow-6: (0 25px 50px -12px rgba($black-rgb-color, 0.25)),
shadow-inset-slight: inset 0 2px 4px 0 rgba($black-rgb-color, 0.06),
shadow-inset-well: inset 0 3px 5px 0 rgba($black-rgb-color, 0.1),
);
// $shadow-outline: 0 0 0 3px rgba(66, 153, 225, 0.5);
$button-radius: 0.5rem; // 8px
@function shadow($name: string) {
@return map-get($shadow, "shadow-" + $name);
}
@mixin depth($name: string) {
box-shadow: shadow($name);
}
@mixin focused {
&::after {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border: 2px solid $control-focus-color;
border-radius: $button-radius;
pointer-events: none;
}
&:focus {
outline: none;
}
input:focus {
outline: none;
}
}

View File

@@ -1,121 +0,0 @@
@use 'func' as *;
// --- Font Families
/**
* Do not directly reference. Use the $font-stack-sans and $font-stack-mono variables instead
*/
$internal-font-stack-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
$internal-font-stack-mono: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
// See export.scss
$font-stack-sans: var(--font-stack-sans);
$font-stack-mono: var(--font-stack-mono);
// --- Text Sizes/Scale
// Chosen to produce integer sizes from a base font size of 16px
$text: (
text-xs: (
size: 0.5rem, // 8px
),
text-s: (
size: 0.75rem, // 12px
),
text-ms: (
size: 0.875rem, // 14px
),
text-m: (
size: 1rem, // 16px
weight: bolder,
),
text-ml: (
size: 1.25rem, // 18px
weight: bolder,
),
text-l: (
size: 1.5rem, // 24px
weight: bolder,
),
text-xl: (
size: 2rem, // 32px
weight: bolder,
),
text-2xl: (
size: 2.5rem, // 40px
weight: bolder,
),
text-3xl: (
size: 3rem, // 48px
weight: bolder,
),
text-4xl: (
size: 4rem, // 64px
weight: bolder,
)
);
$highlight-weight: 600;
@function text($name: string) {
@return map-get(map-get($text, "text-" + #{$name}), size);
}
// --- Line heights
$lh-tight: 1;
$lh-condensed: 1.25;
$lh-normal: 1.5;
// --- Mixins
@mixin _text-base {
font-family: $font-stack-sans;
font-weight: normal;
font-style: normal;
}
// General text
@mixin text($name: string) {
$text-def: map-get($text, "text-" + $name);
$size: map-get($text-def, size);
$weight: map-get($text-def, weight);
@include _text-base;
@if $size {
font-size: $size;
}
@if $weight {
font-weight: $weight;
}
}
@mixin text-mono-m {
font-size: text(m);
font-family: $font-stack-mono;
font-weight: bold;
font-style: normal;
}
@mixin text-mono-s {
font-size: text(s);
font-family: $font-stack-mono;
font-weight: bold;
font-style: normal;
}
// Line heights
@mixin line-height-normal {
line-height: $lh-normal;
}
@mixin line-height-condensed {
line-height: $lh-condensed;
}
@mixin line-height-tight {
line-height: $lh-tight;
}

View File

@@ -1,11 +0,0 @@
/*
* Global CSS values to wrap into the bundle. Should not be imported by dependants
*/
@use 'derived/export.scss';
@use 'typography';
// probably should leave this for the consumer to set?
body, html {
font-size: typography.text(m);
font-family: typography.$font-stack-sans;
}

View File

@@ -1,6 +0,0 @@
/*
* Base SCSS file for external SASS imports (all dependants should import from this file to use the SASS vars)
*/
// css prefix for clarity
@forward 'css/index';

View File

@@ -1,31 +0,0 @@
/**
* Draws the baseline and toplines for a DOM element
*/
.baseline {
position: relative;
&:before {
content: "";
position: absolute;
width: 100%;
height: 1px;
top: 0.2em;
background-color: rgba(red, 0.2);
}
&:after {
content: "";
position: absolute;
width: 100%;
height: 1px;
bottom: 0.2em;
left: 0;
background-color: rgba(red, 0.2);
}
}

View File

@@ -1,9 +0,0 @@
.colorBlock {
display: inline-block;
height: 7rem;
width: 7rem;
padding: 1.5rem;
margin-right: 1rem;
margin-bottom: 1rem;
}

View File

@@ -1,6 +0,0 @@
@use 'baseColors' as *;
.cube {
margin: 1rem;
background-color: $brand-00;
}

View File

@@ -1,9 +0,0 @@
.surface {
display: inline-block;
height: 12rem;
width: 12rem;
padding: 1.5rem;
margin-right: 4rem;
margin-bottom: 4rem;
}

View File

@@ -1,5 +0,0 @@
@use 'baseColors' as *;
.wrapper {
background-color: $brand-00;
}

View File

@@ -1,4 +0,0 @@
import { UnifiedRunner } from '../unified-runner'
// @ts-ignore
window.UnifiedRunner = UnifiedRunner

View File

@@ -1,8 +0,0 @@
.react-devtools-fallback {
width: 100%;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
height: 70%;
}

View File

@@ -1,7 +0,0 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
}
export const cssExports: CssExports;
export default cssExports;

View File

@@ -1,4 +0,0 @@
$cypress-blue: #3380FF;
$cypress-gray: #f6f6f6;
$ct-accent-blue: #4299e1;

View File

@@ -1,23 +0,0 @@
@forward './legacy-styles';
@use './legacy-styles' as *;
$border-color: $metal-20;
$reporter-background-color: white;
$spec-list-background-color: white;
$left-nav-background-color: $metal-05;
$resizer-hover-color: $chill-40;
$aut-background-color: white;
$aut-drop-shadow: shadow(bordered);
$runner-ct-header-height: 46px;
/**
* Utility classes
*/
.display-none {
display: none !important;
}

View File

@@ -1,69 +0,0 @@
{
"extends": "../ts/tsconfig.json",
"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": true,
"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,
"skipLibCheck": true,
"noErrorTruncation": true,
"experimentalDecorators": true
// "noResolve": true
},
"include": [
"./lib/*.ts",
"./src*.ts",
"./src*.tsx",
"./index.ts",
"./index.d.ts",
"./../ts/index.d.ts"
],
"exclude": [
"dist",
"test"
]
}

View File

@@ -1,101 +0,0 @@
process.env.NO_LIVERELOAD = '1'
import _ from 'lodash'
import path from 'path'
import type webpack from 'webpack'
import { getCommonConfig, getCopyWebpackPlugin } from '@packages/web-config/webpack.config.base'
import * as cyIcons from '@packages/icons'
const commonConfig = getCommonConfig()
const CopyWebpackPlugin = getCopyWebpackPlugin()
// @ts-ignore
const babelLoader = _.find(commonConfig.module.rules, (rule) => {
// @ts-ignore
return _.includes(rule.use.loader, 'babel-loader')
})
// @ts-ignore
babelLoader.use.options.plugins.push([require.resolve('babel-plugin-prismjs'), {
languages: ['javascript', 'coffeescript', 'typescript', 'jsx', 'tsx'],
plugins: ['line-numbers', 'line-highlight'],
theme: 'default',
css: false,
}])
const { pngRule, nonPngRules } = commonConfig!.module!.rules!.reduce<{
nonPngRules: webpack.RuleSetRule[]
pngRule: webpack.RuleSetRule | undefined
}>((acc, rule) => {
if (rule?.test?.toString().includes('png')) {
return {
...acc,
pngRule: rule,
}
}
return {
...acc,
nonPngRules: [...acc.nonPngRules, rule],
}
}, {
nonPngRules: [],
pngRule: undefined,
})
if (!pngRule || !pngRule.use) {
throw Error('Could not find png loader')
}
(pngRule.use as webpack.RuleSetLoader[])[0].options = {
name: '[name].[ext]',
outputPath: 'img',
publicPath: '/__cypress/runner/img/',
}
// @ts-ignore
const config: webpack.Configuration = {
...commonConfig,
module: {
rules: [
...nonPngRules,
pngRule,
{
test: /index\.js/,
exclude: /node_modules/,
},
],
},
entry: {
cypress_runner: [path.resolve(__dirname, 'src/index.js')],
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
chunkFilename: '[name].[chunkhash].js',
},
}
// @ts-ignore
config.plugins = [
// @ts-ignore
...config.plugins,
new CopyWebpackPlugin([{
// @ts-ignore // There's a race condition in how these types are generated.
from: cyIcons.getPathToFavicon('favicon.ico'),
}]),
]
config.resolve = {
...config.resolve,
alias: {
bluebird: require.resolve('bluebird'),
lodash: require.resolve('lodash'),
mobx: require.resolve('mobx'),
'mobx-react': require.resolve('mobx-react'),
react: require.resolve('react'),
'react-dom': require.resolve('react-dom'),
},
}
export default config

View File

@@ -1,137 +0,0 @@
{
"plugins": [
"cypress",
"@cypress/dev"
],
"extends": [
"plugin:@cypress/dev/general",
"plugin:@cypress/dev/tests",
"plugin:@cypress/dev/react",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"../reporter/src/.eslintrc.json"
],
"parser": "@typescript-eslint/parser",
"env": {
"cypress/globals": true
},
"rules": {
"react/display-name": "off",
"react/function-component-definition": [
"error",
{
"namedComponents": "arrow-function",
"unnamedComponents": "arrow-function"
}
],
"react/jsx-boolean-value": [
"error",
"always"
],
"react/jsx-closing-bracket-location": [
"error",
"line-aligned"
],
"react/jsx-closing-tag-location": "error",
"react/jsx-curly-brace-presence": [
"error",
{
"props": "never",
"children": "never"
}
],
"react/jsx-curly-newline": "error",
"react/jsx-filename-extension": [
"warn",
{
"extensions": [
".js",
".jsx",
".tsx"
]
}
],
"react/jsx-first-prop-new-line": "error",
"react/jsx-max-props-per-line": [
"error",
{
"maximum": 1,
"when": "multiline"
}
],
"react/jsx-no-bind": [
"error",
{
"ignoreDOMComponents": true
}
],
"react/jsx-no-useless-fragment": "error",
"react/jsx-one-expression-per-line": [
"error",
{
"allow": "literal"
}
],
"react/jsx-sort-props": [
"error",
{
"callbacksLast": true,
"ignoreCase": true,
"noSortAlphabetically": true,
"reservedFirst": true
}
],
"react/jsx-tag-spacing": [
"error",
{
"closingSlash": "never",
"beforeSelfClosing": "always"
}
],
"react/jsx-wrap-multilines": [
"error",
{
"declaration": "parens-new-line",
"assignment": "parens-new-line",
"return": "parens-new-line",
"arrow": "parens-new-line",
"condition": "parens-new-line",
"logical": "parens-new-line",
"prop": "parens-new-line"
}
],
"react/no-array-index-key": "error",
"react/no-unescaped-entities": "off",
"react/prop-types": "off",
"quote-props": [
"error",
"as-needed"
]
},
"overrides": [
{
"files": [
"lib/*"
],
"rules": {
"no-console": 1
}
},
{
"files": [
"**/*.json"
],
"rules": {
"quotes": "off",
"comma-dangle": "off"
}
},
{
"files": "*.tsx",
"rules": {
"no-unused-vars": "off",
"react/jsx-no-bind": "off"
}
}
]
}

View File

@@ -1,6 +0,0 @@
# Runner Shared
This is an old package, deprecated in favor of `@packages/app`. It has two remaining responsibilities before it can be entirely removed:
1. Contains `dom.js`, which uses proprietary webpack loaders and cannot easily be imported with Vite (dev server in `@packages/app`). This is bundled via webpack in either `@packages/runner` or `@packages/runner-ct`. Once `dom.js` is free of webpack-specific loader code, we should move it to `@packages/app`.
2. Contains UI code for Cypress Studio, which was marked as experimental in Cypress 9.x and won't be part of Cypress 10.x initially. It will return at a later date. Until then, the code will be here. It's not currently used in the app.

View File

@@ -1,34 +0,0 @@
{
"name": "@packages/runner-shared",
"version": "0.0.0-development",
"private": true,
"main": "src/index.ts",
"scripts": {
"test": "yarn test-unit",
"test-unit": "mocha --config test/.mocharc.json src/*.spec.* src/**/*.spec.* --exit"
},
"dependencies": {},
"devDependencies": {
"@cypress/react-tooltip": "0.5.3",
"@packages/driver": "0.0.0-development",
"@packages/socket": "0.0.0-development",
"@packages/web-config": "0.0.0-development",
"@popperjs/core": "2.9.2",
"ansi-to-html": "0.6.14",
"chai": "4.2.0",
"chai-enzyme": "1.0.0-beta.1",
"classnames": "2.3.1",
"enzyme": "3.11.0",
"enzyme-adapter-react-16": "1.15.2",
"lodash": "^4.17.21",
"mobx": "5.15.4",
"mobx-react": "6.1.8",
"mocha": "7.0.1",
"nanoid": "3.1.31",
"react": "16.8.6",
"react-dom": "16.8.6",
"react-popper": "2.2.5",
"react-shadow-dom-retarget-events": "1.0.11",
"sinon": "7.5.0"
}
}

View File

@@ -1,3 +0,0 @@
export * from './dom'
export * from './studio'

Binary file not shown.

Before

Width:  |  Height:  |  Size: 387 KiB

View File

@@ -1,5 +0,0 @@
export * from './studio'
export * from './studio-modals'
export * from './studio-recorder'

View File

@@ -1,186 +0,0 @@
import { observer } from 'mobx-react'
import React, { Component } from 'react'
import { Dialog } from '@reach/dialog'
import VisuallyHidden from '@reach/visually-hidden'
import './studio-modals.scss'
@observer
export class StudioInstructionsModal extends Component {
render () {
return (
<Dialog
className='studio-modal studio-instructions-modal'
aria-label='Start Studio'
isOpen={this.props.open}
onDismiss={this.props.close}
>
<div className='body'>
<h1 className='title'>
<i className='fas fa-magic icon' />
{' '}
Studio
{' '}
<span className='beta'>BETA</span>
</h1>
<div className='content center'>
<div className='text'>
Generate and save commands directly to your test suite by interacting with your app as an end user would. Right click on an element to add an assertion. Studio will track events that generate the following commands:
</div>
<div className='text center-box'>
<ul>
<li>
<pre>.check()</pre>
</li>
<li>
<pre>.click()</pre>
</li>
<li>
<pre>.select()</pre>
</li>
<li>
<pre>.type()</pre>
</li>
<li>
<pre>.uncheck()</pre>
</li>
</ul>
</div>
<div className='text'>
This feature is currently in Beta and we will be adding more commands and abilities in the future. Your
{' '}
<a href='https://on.cypress.io/studio-beta' target='_blank' rel="noreferrer">feedback</a>
{' '}
will be highly influential to our team.
</div>
</div>
<div className='controls'>
<button className='cancel' onClick={this.props.close}>Close</button>
</div>
</div>
<button className='close-button' onClick={this.props.close}>
<VisuallyHidden>Close</VisuallyHidden>
<span aria-hidden={true}>
<i className='fas fa-times' />
</span>
</button>
</Dialog>
)
}
}
@observer
export class StudioInitModal extends Component {
render () {
return (
<Dialog
className='studio-modal studio-init-modal'
aria-label='Start Studio'
isOpen={this.props.eventManager.studioRecorder.initModalIsOpen}
onDismiss={this._close}
>
<div className='body'>
<h1 className='title'>
<i className='fas fa-magic icon' />
{' '}
Studio
{' '}
<span className='beta'>BETA</span>
</h1>
<div className='gif'>
<img src={require('../static/studio.gif')} alt='Studio' />
</div>
<div className='content center'>
<div className='text'>
Generate Cypress commands by interacting with your site as an end user would. Then, save these commands directly to your test file.
</div>
<button className='btn-main' onClick={this._start}>
Get Started
</button>
</div>
</div>
<button className='close-button' onClick={this._close}>
<VisuallyHidden>Close</VisuallyHidden>
<span aria-hidden={true}>
<i className='fas fa-times' />
</span>
</button>
</Dialog>
)
}
_close = () => {
this.props.eventManager.studioRecorder.closeInitModal()
this.props.eventManager.studioRecorder.clearRunnableIds()
}
_start = () => this.props.eventManager.emit('studio:start')
}
@observer
export class StudioSaveModal extends Component {
state = {
name: '',
}
render () {
const { name } = this.state
return (
<Dialog
className='studio-modal studio-save-modal'
aria-label='Save New Test'
isOpen={this.props.eventManager.studioRecorder.saveModalIsOpen}
onDismiss={this.props.eventManager.studioRecorder.closeSaveModal}
>
<div className='body'>
<h1 className='title'>
<i className='fas fa-magic icon' />
{' '}
Save New Test
</h1>
<div className='content'>
<form onSubmit={this._save}>
<div className='text'>
<label className='text-strong' htmlFor='testName'>Test Name</label>
<input id='testName' type='text' value={name} required={true} onChange={this._onInputChange} />
</div>
<div className='center'>
<button className='btn-main' type='submit' disabled={!name}>
Save Test
</button>
</div>
</form>
</div>
</div>
<button className='close-button' onClick={this.props.eventManager.studioRecorder.closeSaveModal}>
<VisuallyHidden>Close</VisuallyHidden>
<span aria-hidden={true}>
<i className='fas fa-times' />
</span>
</button>
</Dialog>
)
}
_onInputChange = (e) => {
this.setState({ name: e.target.value })
}
_save = (e) => {
e.preventDefault()
const { name } = this.state
if (!name) return
this.props.eventManager.studioRecorder.save(name)
}
}
export const StudioModals = (props) => (
<>
<StudioInitModal eventManager={props.eventManager} />
<StudioSaveModal eventManager={props.eventManager} />
</>
)

View File

@@ -1,141 +0,0 @@
$font-sans: 'Mulish', 'Helvetica Neue', 'Arial', sans-serif;
$open-sans: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
.studio-modal {
max-width: 35em;
.body {
font-family: $font-sans;
margin-bottom: 2em;
margin-top: -0.8em;
.title {
color: #565554;
font-family: $open-sans;
font-weight: 600;
padding: 0 1em;
.icon {
color: #3386d4;
margin-right: 5px;
}
.beta {
color: #959595;
font-weight: 400;
}
}
.gif {
margin: 15px 0;
width: 100%;
img {
width: 100%;
}
}
.content {
.text {
color: #6c6c6c;
padding: 0.5em 1em;
.text-strong {
color: #565554;
}
input {
border: 1px solid #9d9ea9;
border-radius: 2px;
box-sizing: border-box;
color: #6c6c6c;
display: block;
font-size: 16px;
font-family: $font-sans;
margin-top: 8px;
padding: 4px;
width: 100%;
&:focus {
outline: none;
}
}
ul {
font-size: 16px;
line-height: 22px;
text-align: left;
}
}
.center-box {
display: flex;
justify-content: center;
}
.btn-main {
background-color: #3386d4;
border-radius: 0.25em;
color: #fff;
font-family: $font-sans;
padding: 0.8em 4em;
margin-top: 1em;
&:hover {
background: darken(#3386d4, 10%);
}
&:focus {
outline: none;
}
&[disabled],
&[disabled]:hover,
&[disabled]:active {
background-color: #3386d4;
opacity: 0.5;
}
}
}
.center {
text-align: center;
}
}
.close-button {
color: #959595;
}
&.studio-save-modal {
max-width: 25em;
min-width: 20em;
.body {
margin-bottom: 1em;
.content .text {
border-top: 1px solid #e1e2e4;
font-size: 16px;
margin-top: 0.8em;
padding-top: 1em;
}
}
}
&.studio-instructions-modal {
.body {
margin-bottom: 0;
.content {
padding-top: 0.5em;
padding-bottom: 0.2em;
}
button {
font-family: $font-sans;
font-size: 12px;
}
}
}
}

View File

@@ -1,7 +0,0 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
}
export const cssExports: CssExports;
export default cssExports;

View File

@@ -1,157 +0,0 @@
import React from 'react'
import { shallow } from 'enzyme'
import sinon from 'sinon'
import { Dialog } from '@reach/dialog'
import { createEventManager } from '../../test/utils'
import { StudioModals, StudioInstructionsModal, StudioInitModal, StudioSaveModal } from './studio-modals'
describe('<StudioModals />', () => {
let eventManager
beforeEach(() => {
eventManager = createEventManager()
sinon.stub(eventManager, 'emit')
})
afterEach(() => {
eventManager.studioRecorder.cancel()
sinon.restore()
})
it('renders init and save modals', () => {
const component = shallow(<StudioModals eventManager={eventManager} />)
expect(component.find(StudioInitModal)).to.exist
expect(component.find(StudioSaveModal)).to.exist
})
describe('<StudioInstructionsModal />', () => {
it('passes open prop to dialog', () => {
const component = shallow(<StudioInstructionsModal open={false} close={sinon.stub()} />)
expect(component.find(Dialog)).to.have.prop('isOpen', false)
component.setProps({ open: true })
expect(component.find(Dialog)).to.have.prop('isOpen', true)
})
it('calls close prop on close', () => {
const close = sinon.stub()
const component = shallow(<StudioInstructionsModal open={true} close={close} />)
component.find('.close-button').simulate('click')
expect(close).to.be.called
})
})
describe('<StudioInitModal />', () => {
it('is not open by default', () => {
const component = shallow(<StudioInitModal eventManager={eventManager} />)
expect(component.find(Dialog)).to.have.prop('isOpen', false)
})
it('is open and closes with studio recorder variable', () => {
eventManager.studioRecorder.initModalIsOpen = true
const component = shallow(<StudioInitModal eventManager={eventManager} />)
expect(component.find(Dialog)).to.have.prop('isOpen', true)
eventManager.studioRecorder.closeInitModal()
expect(component.find(Dialog)).to.have.prop('isOpen', false)
})
it('closes and clears studio runnable ids when close is clicked', () => {
sinon.stub(eventManager.studioRecorder, 'clearRunnableIds')
eventManager.studioRecorder.initModalIsOpen = true
const component = shallow(<StudioInitModal eventManager={eventManager} />)
component.find('.close-button').simulate('click')
expect(component.find(Dialog)).to.have.prop('isOpen', false)
expect(eventManager.studioRecorder.initModalIsOpen).to.equal(false)
expect(eventManager.studioRecorder.clearRunnableIds).to.be.called
})
it('emits studio:start when start button is clicked', () => {
eventManager.studioRecorder.initModalIsOpen = true
const component = shallow(<StudioInitModal eventManager={eventManager} />)
component.find('.btn-main').simulate('click')
expect(eventManager.emit).to.be.calledWith('studio:start')
})
})
describe('<StudioSaveModal />', () => {
it('is not open by default', () => {
const component = shallow(<StudioSaveModal eventManager={eventManager} />)
expect(component.find(Dialog)).to.have.prop('isOpen', false)
})
it('is open and closes with studio recorder variable', () => {
eventManager.studioRecorder.saveModalIsOpen = true
const component = shallow(<StudioSaveModal eventManager={eventManager} />)
expect(component.find(Dialog)).to.have.prop('isOpen', true)
eventManager.studioRecorder.closeSaveModal()
expect(component.find(Dialog)).to.have.prop('isOpen', false)
})
it('closes when close is clicked', () => {
eventManager.studioRecorder.saveModalIsOpen = true
const component = shallow(<StudioSaveModal eventManager={eventManager} />)
component.find('.close-button').simulate('click')
expect(component.find(Dialog)).to.have.prop('isOpen', false)
expect(eventManager.studioRecorder.saveModalIsOpen).to.equal(false)
})
context('form', () => {
beforeEach(() => {
sinon.stub(eventManager.studioRecorder, 'save')
eventManager.studioRecorder.saveModalIsOpen = true
})
it('updates input when typed into', () => {
const component = shallow(<StudioSaveModal eventManager={eventManager} />)
component.find('input').simulate('change', { target: { value: 'my test name' } })
expect(component.find('input')).to.have.prop('value', 'my test name')
})
it('calls studio recorder save with inputted text on submit', () => {
const component = shallow(<StudioSaveModal eventManager={eventManager} />)
component.find('input').simulate('change', { target: { value: 'my test name' } })
expect(component.find('.btn-main')).to.have.prop('disabled', false)
component.find('form').simulate('submit', { preventDefault: () => {} })
expect(eventManager.studioRecorder.save).to.be.calledWith('my test name')
})
it('disables form when there is no input', () => {
const component = shallow(<StudioSaveModal eventManager={eventManager} />)
expect(component.find('.btn-main')).to.have.prop('disabled', true)
component.find('form').simulate('submit', { preventDefault: () => {} })
expect(eventManager.studioRecorder.save).not.to.be.called
})
})
})
})

View File

@@ -1,139 +0,0 @@
import React, { Component } from 'react'
import { observer } from 'mobx-react'
import Tooltip from '@cypress/react-tooltip'
import cs from 'classnames'
import { StudioInstructionsModal } from './studio-modals'
@observer
class Studio extends Component {
state = {
modalOpen: false,
copySuccess: false,
}
render () {
const { model, hasUrl } = this.props
const { modalOpen, copySuccess } = this.state
return (
<div className='header-popup studio'>
<StudioInstructionsModal open={modalOpen} close={this._closeModal} />
<div className='text-block'>
<span className={cs('icon', { 'is-active': model.isActive && !model.isFailed && hasUrl })}>
<i className='fas' />
</span>
{' '}
<span className='title'>Studio</span>
{' '}
<span className='beta'>Beta</span>
</div>
<div className='text-block'>
<a href='#' className={cs('available-commands', { 'link-disabled': model.isLoading })} onClick={this._showModal}>Available Commands</a>
</div>
<div className='text-block'>
<a href={!model.isLoading ? 'https://on.cypress.io/studio-beta' : undefined} target='_blank' className={cs('give-feedback', { 'link-disabled': model.isLoading })} rel="noreferrer">Give Feedback</a>
</div>
<div className='studio-controls'>
<Tooltip
title='Close Studio'
className='cy-tooltip'
visible={model.isLoading ? false : null}
>
<button
className='header-button button-studio button-studio-close'
disabled={model.isLoading}
onClick={this._close}
>
<i className='fas fa-times' />
</button>
</Tooltip>
<Tooltip
title='Restart'
className='cy-tooltip'
visible={model.isLoading ? false : null}
>
<button
className='header-button button-studio button-studio-restart'
disabled={model.isLoading}
onClick={this._restart}
>
<i className='fas fa-undo' />
</button>
</Tooltip>
<Tooltip
title={copySuccess ? 'Commands Copied!' : 'Copy Commands to Clipboard'}
className='cy-tooltip'
visible={model.isLoading || model.isEmpty ? false : null}
updateCue={copySuccess}
>
<button
className={cs('header-button button-studio button-studio-copy', {
'button-success': copySuccess,
})}
disabled={model.isLoading || model.isEmpty}
onClick={this._copy}
onMouseLeave={this._endCopySuccess}
>
<i className={copySuccess ? 'fas fa-check' : 'fas fa-copy'} />
</button>
</Tooltip>
<Tooltip
title='Save Commands'
className='cy-tooltip'
visible={model.isLoading || model.isEmpty ? false : null}
>
<button
className='header-button button-studio button-studio-save'
disabled={model.isLoading || model.isEmpty}
onClick={this._save}
>
<i className='fas fa-save' />
</button>
</Tooltip>
</div>
</div>
)
}
_showModal = (e) => {
e.preventDefault()
if (this.props.model.isLoading) return
this.setState({ modalOpen: true })
}
_closeModal = () => {
this.setState({ modalOpen: false })
}
_close = () => {
this.props.eventManager.emit('studio:cancel')
}
_restart = () => {
this.props.model.reset()
this.props.eventManager.emit('restart')
}
_copy = () => {
if (this.state.copySuccess) return
this.props.eventManager.emit('studio:copy:to:clipboard', () => {
this.setState({ copySuccess: true })
})
}
_save = () => {
this.props.model.startSave()
}
_endCopySuccess = () => {
if (this.state.copySuccess) {
this.setState({ copySuccess: false })
}
}
}
export { Studio }

View File

@@ -1,156 +0,0 @@
import React from 'react'
import { shallow } from 'enzyme'
import sinon from 'sinon'
import Tooltip from '@cypress/react-tooltip'
import { Studio } from './studio'
import { StudioInstructionsModal } from './studio-modals'
import { createEventManager } from '../../test/utils'
const createModel = (props) => {
return {
isActive: false,
isLoading: false,
reset: sinon.stub(),
startSave: sinon.stub(),
...props,
}
}
describe('<Studio />', () => {
let eventManager
beforeEach(() => {
eventManager = createEventManager()
})
context('icon', () => {
it('is not active when studio is not active', () => {
const component = shallow(<Studio model={createModel({ isActive: false })} />)
expect(component.find('.icon')).not.to.have.className('is-active')
})
it('is not active when there is no url', () => {
const component = shallow(<Studio model={createModel({ isActive: true })} hasUrl={false} />)
expect(component.find('.icon')).not.to.have.className('is-active')
})
it('is active when studio is active and there is a url', () => {
const component = shallow(<Studio model={createModel({ isActive: true })} hasUrl={true} />)
expect(component.find('.icon')).to.have.className('is-active')
})
it('is not active when test has failed', () => {
const component = shallow(<Studio model={createModel({ isActive: true, isFailed: true })} hasUrl={true} />)
expect(component.find('.icon')).not.to.have.className('is-active')
})
})
context('header links', () => {
it('does not show modal by default', () => {
const component = shallow(<Studio model={createModel({ isActive: true })} />)
expect(component.find(StudioInstructionsModal)).to.have.prop('open', false)
})
it('shows model when available commands is clicked', () => {
const component = shallow(<Studio model={createModel({ isActive: true })} />)
component.find('.available-commands').simulate('click', { preventDefault: () => {} })
expect(component.find(StudioInstructionsModal)).to.have.prop('open', true)
})
it('disables available commands link while loading', () => {
const component = shallow(<Studio model={createModel({ isLoading: true })} />)
expect(component.find('.available-commands')).to.have.className('link-disabled')
component.find('.available-commands').simulate('click', { preventDefault: () => {} })
expect(component.find(StudioInstructionsModal)).to.have.prop('open', false)
})
it('disables feedback link while loading', () => {
const component = shallow(<Studio model={createModel({ isLoading: true })} />)
expect(component.find('.give-feedback')).to.have.className('link-disabled')
expect(component.find('.give-feedback')).not.to.have.prop('href')
})
})
context('controls', () => {
beforeEach(() => {
sinon.stub(eventManager, 'emit')
})
afterEach(() => {
sinon.restore()
})
it('disables all controls while studio is loading', () => {
const component = shallow(<Studio model={createModel({ isLoading: true })} />)
expect(component.find('.button-studio-close')).to.have.prop('disabled', true)
expect(component.find('.button-studio-restart')).to.have.prop('disabled', true)
expect(component.find('.button-studio-save')).to.have.prop('disabled', true)
})
it('renders tooltips', () => {
const component = shallow(<Studio model={createModel({ isActive: true })} eventManager={eventManager} />)
expect(component.find(Tooltip).at(0)).to.have.prop('title', 'Close Studio')
expect(component.find(Tooltip).at(1)).to.have.prop('title', 'Restart')
expect(component.find(Tooltip).at(2)).to.have.prop('title', 'Copy Commands to Clipboard')
expect(component.find(Tooltip).at(3)).to.have.prop('title', 'Save Commands')
})
it('hides all tooltips while studio is loading', () => {
const component = shallow(<Studio model={createModel({ isLoading: true })} eventManager={eventManager} />)
expect(component.find(Tooltip).at(0)).to.have.prop('visible', false)
expect(component.find(Tooltip).at(1)).to.have.prop('visible', false)
expect(component.find(Tooltip).at(2)).to.have.prop('visible', false)
expect(component.find(Tooltip).at(3)).to.have.prop('visible', false)
})
it('emits studio:cancel when close button is clicked', () => {
const component = shallow(<Studio model={createModel({ isActive: true })} eventManager={eventManager} />)
component.find('.button-studio-close').simulate('click')
expect(eventManager.emit).to.be.calledWith('studio:cancel')
})
it('resets studio recorder and emits restart when restart button is clicked', () => {
const model = createModel({ isActive: true })
const component = shallow(<Studio model={model} eventManager={eventManager} />)
component.find('.button-studio-restart').simulate('click')
expect(model.reset).to.be.called
expect(eventManager.emit).to.be.calledWith('restart')
})
it('starts copy to clipboard process when copy button is clicked', () => {
const component = shallow(<Studio model={createModel({ isActive: true })} eventManager={eventManager} />)
component.find('.button-studio-copy').simulate('click')
expect(eventManager.emit).to.be.calledWith('studio:copy:to:clipboard')
})
it('starts studio recorder saving when save button is clicked', () => {
const model = createModel({ isActive: true })
const component = shallow(<Studio model={model} eventManager={eventManager} />)
component.find('.button-studio-save').simulate('click')
expect(model.startSave).to.be.called
})
})
})

View File

@@ -1,7 +0,0 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'specsList': string;
}
export const cssExports: CssExports;
export default cssExports;

View File

@@ -1,5 +0,0 @@
{
"file": "test/helper.js",
"require": "../web-config/node-register",
"extension": "ts,jsx,tsx,js"
}

View File

@@ -1,48 +0,0 @@
import { returnMockRequire, register } from '@packages/web-config/node-jsdom-setup'
import 'regenerator-runtime/runtime'
import sinon from 'sinon'
const driverMock = {}
register({
enzyme: require('enzyme'),
EnzymeAdapter: require('enzyme-adapter-react-16'),
chaiEnzyme: require('chai-enzyme'),
requireOverride (depPath) {
if (depPath === '@packages/driver') {
return driverMock
}
// TODO: refactor w/ regex
if (depPath.includes('.gif')) {
return ''
}
},
})
returnMockRequire('@packages/socket/lib/browser', {
client () {
return { emit: () => {}, on: () => {} }
},
})
const _useFakeTimers = sinon.useFakeTimers
let timers = []
sinon.useFakeTimers = function (...args) {
const ret = _useFakeTimers.apply(this, args)
timers.push(ret)
}
beforeEach(() => {
driverMock.$ = sinon.stub().throws('$ called without being stubbed')
})
afterEach(() => {
timers.forEach((clock) => {
return clock.restore()
})
timers = []
})

View File

@@ -1,21 +0,0 @@
import $Cypress from '@packages/driver'
import { EventManager } from '@packages/app/src/runner/event-manager'
import type { Socket } from '@packages/socket/lib/browser'
import { StudioRecorder } from '../src/studio'
import * as MobX from 'mobx'
export const StubWebsocket = new Proxy<Socket>(Object.create(null), {
get: (obj, prop) => {
throw Error(`Cannot access ${String(prop)} on StubWebsocket!`)
},
})
export const createEventManager = () => {
return new EventManager(
$Cypress,
MobX,
{}, // TODO: Bring back "Cypress Studio" and integrate with 10.x runner // selectorPlaygroundModel
StudioRecorder,
StubWebsocket,
)
}

View File

@@ -1,7 +0,0 @@
{
"extends": "../ts/tsconfig.dom.json",
"compilerOptions": {
"jsx": "react",
"experimentalDecorators": true
}
}

View File

@@ -4,4 +4,6 @@ This is an old package, deprecated in favor of `@packages/app`. It has two remai
1. Bundles `@packages/reporter` and `@packages/driver` via webpack. Once those can be directly imported to `@packages/app`, we can remove this.
2. Bundles styles for `@packages/reporter`, loaded in `main.scss`. Ideally, reporter should import its own styles.
3. Some existing tests in `cypress/e2e` should be migrated to `@packages/app/cypress/e2e/runner`.
3. Contains `dom.js`, which uses proprietary webpack loaders and cannot easily be imported with Vite (dev server in `@packages/app`). Once `dom.js` is free of webpack-specific loader code, we should move it to `@packages/app`.
4. Contains Cypress Studio Recorder code, which was marked as experimental in Cypress 9.x and won't be part of Cypress 10.x initially. It will return at a later date. Until then, the code will be here. It's not currently used in the app. @see https://github.com/cypress-io/cypress/issues/22870
5. Contains Legacy Cypress styles, most of these can likely be removed.

View File

@@ -19,11 +19,9 @@
"@fortawesome/fontawesome-free": "6.0.0",
"@packages/driver": "0.0.0-development",
"@packages/icons": "0.0.0-development",
"@packages/network": "0.0.0-development",
"@packages/reporter": "0.0.0-development",
"@packages/rewriter": "0.0.0-development",
"@packages/socket": "0.0.0-development",
"@packages/web-config": "0.0.0-development",
"@popperjs/core": "2.9.2",
"babel-plugin-prismjs": "1.0.2",
"bluebird": "3.5.3",
"classnames": "2.3.1",
@@ -36,6 +34,8 @@
"prop-types": "15.7.2",
"react": "16.8.6",
"react-dom": "16.8.6",
"react-popper": "2.2.5",
"react-shadow-dom-retarget-events": "1.0.11",
"rimraf": "3.0.2",
"webpack": "^4.44.2",
"webpack-cli": "3.3.2"

View File

@@ -3,12 +3,12 @@ import retargetEvents from 'react-shadow-dom-retarget-events'
import $Cypress from '@packages/driver'
import $dimensions from './dimensions'
import { selectorPlaygroundHighlight } from './selector-playground/highlight'
import { studioAssertionsMenu } from './studio/assertions-menu'
import { selectorPlaygroundHighlight } from '../selector-playground/highlight'
import { studioAssertionsMenu } from '../studio/assertions-menu'
// The '!' tells webpack to disable normal loaders, and keep loaders with `enforce: 'pre'` and `enforce: 'post'`
// This disables the CSSExtractWebpackPlugin and allows us to get the CSS as a raw string instead of saving it to a separate file.
import selectorPlaygroundCSS from '!./selector-playground/selector-playground.scss'
import studioAssertionsMenuCSS from '!./studio/assertions-menu.scss'
import selectorPlaygroundCSS from '!../selector-playground/selector-playground.scss'
import studioAssertionsMenuCSS from '!../studio/assertions-menu.scss'
const $ = $Cypress.$
const styles = (styleString) => {

View File

@@ -0,0 +1 @@
export * from './dom'

View File

@@ -1,3 +1,3 @@
import { UnifiedRunner } from '@packages/runner-ct/unified-runner'
import { UnifiedRunner } from '../unified-runner'
window.UnifiedRunner = UnifiedRunner

View File

@@ -0,0 +1,5 @@
// Studio tests have been removed with v10 update.
// You can find the tests in the PR below.
// @see https://github.com/cypress-io/cypress/pull/9542
export * from './studio-recorder'

View File

@@ -1,14 +1,13 @@
import React from 'react'
import ReactDOM from 'react-dom'
import $Cypress from '@packages/driver'
import {
StudioRecorder,
dom,
} from '@packages/runner-shared'
import { Reporter } from '@packages/reporter/src/main'
import shortcuts from '@packages/reporter/src/lib/shortcuts'
import * as MobX from 'mobx'
import { StudioRecorder } from './src/studio'
import { dom } from './src/dom'
export const UnifiedRunner = {
CypressJQuery: $Cypress.$,

Some files were not shown because too many files have changed in this diff Show More