mirror of
https://github.com/cypress-io/cypress.git
synced 2026-05-18 22:28:38 -05:00
Merge branch 'master' into pln/docs-index
# Conflicts: # docs/package.json # docs/source/_data/menu.yml # docs/themes/cypress/languages/en.yml
This commit is contained in:
@@ -1,22 +0,0 @@
|
||||
# There are multiple packages and for each package we might have
|
||||
# unit, integration and e2e tests
|
||||
#
|
||||
# If we can control only a single variable, and it should be our command
|
||||
env:
|
||||
- CMD="test -- --package packages/coffee/"
|
||||
- CMD="test -- --package packages/desktop-gui/"
|
||||
# TODO fix driver tests
|
||||
- CMD="test -- --package packages/electron/"
|
||||
# TODO clarify unit vs E2E tests in example project
|
||||
- CMD="test -- --package packages/extension/"
|
||||
- CMD="test -- --package packages/https-proxy/"
|
||||
- CMD="test -- --package packages/launcher/"
|
||||
- CMD="test -- --package packages/reporter/"
|
||||
- CMD="test -- --package packages/runner/"
|
||||
# TODO fix server tests
|
||||
- CMD="test -- --package packages/socket/"
|
||||
- CMD="test -- --package packages/static/"
|
||||
|
||||
command:
|
||||
- echo "Running $CMD"
|
||||
- npm run all $CMD
|
||||
@@ -46,8 +46,6 @@ Each package is responsible for building itself and testing itself and can do so
|
||||
|
||||
**clean-deps**: Remove any dependencies installed (usually by npm or bower)
|
||||
|
||||
**clean-all**: Run *clean* and *clean-deps* scripts
|
||||
|
||||
**test-all**: Run all tests in watch mode
|
||||
|
||||
**test-all-once**: Run all tests
|
||||
|
||||
+64
-7
@@ -5,14 +5,10 @@ machine:
|
||||
dependencies:
|
||||
# CircleCI caching
|
||||
# https://circleci.com/docs/1.0/how-cache-works/
|
||||
pre:
|
||||
# for "simple" parallel builds on CircleCI
|
||||
# https://github.com/michaelcontento/circleci-matrix
|
||||
# also see file .circleci-matrix.yml
|
||||
- curl -fsSL https://git.io/v2Ifn | bash
|
||||
cache_directories:
|
||||
# downloaded Electron binary
|
||||
- "~/.electron"
|
||||
- docs/node_modules
|
||||
# could not use wildcard format, so list every subfolder
|
||||
- packages/coffee/node_modules
|
||||
- packages/desktop-gui/node_modules
|
||||
@@ -41,6 +37,67 @@ test:
|
||||
## runner (5)
|
||||
## server (5, 6)
|
||||
override:
|
||||
- circleci-matrix :
|
||||
#
|
||||
# things to run in the 1st CI container
|
||||
#
|
||||
# build docs site (fast)
|
||||
- if [ $CIRCLE_NODE_INDEX == 0 ]; then cd docs && npm install; fi:
|
||||
parallel: true
|
||||
# TODO E2E tests
|
||||
|
||||
# run linter (fast)
|
||||
- if [ $CIRCLE_NODE_INDEX == 0 ]; then npm run all lint; fi:
|
||||
parallel: true
|
||||
# run unit tests (fast)
|
||||
# separate commands for better GUI view
|
||||
- if [ $CIRCLE_NODE_INDEX == 0 ]; then npm run all test -- --package coffee; fi:
|
||||
parallel: true
|
||||
|
||||
- if [ $CIRCLE_NODE_INDEX == 0 ]; then npm run all test -- --package desktop-gui; fi:
|
||||
parallel: true
|
||||
|
||||
- if [ $CIRCLE_NODE_INDEX == 0 ]; then npm run all test -- --package electron; fi:
|
||||
parallel: true
|
||||
|
||||
- if [ $CIRCLE_NODE_INDEX == 0 ]; then npm run all test -- --package extension; fi:
|
||||
parallel: true
|
||||
|
||||
- if [ $CIRCLE_NODE_INDEX == 0 ]; then npm run all test -- --package https-proxy; fi:
|
||||
parallel: true
|
||||
|
||||
- if [ $CIRCLE_NODE_INDEX == 0 ]; then npm run all test -- --package launcher; fi:
|
||||
parallel: true
|
||||
|
||||
- if [ $CIRCLE_NODE_INDEX == 0 ]; then npm run all test -- --package reporter; fi:
|
||||
parallel: true
|
||||
|
||||
- if [ $CIRCLE_NODE_INDEX == 0 ]; then npm run all test -- --package runner; fi:
|
||||
parallel: true
|
||||
|
||||
- if [ $CIRCLE_NODE_INDEX == 0 ]; then npm run all test -- --package server; fi:
|
||||
parallel: true
|
||||
|
||||
- if [ $CIRCLE_NODE_INDEX == 0 ]; then npm run all test -- --package socket; fi:
|
||||
parallel: true
|
||||
|
||||
- if [ $CIRCLE_NODE_INDEX == 0 ]; then npm run all test -- --package static; fi:
|
||||
parallel: true
|
||||
|
||||
- if [ $CIRCLE_NODE_INDEX == 0 ]; then npm run all test-integration-once -- --package server; fi:
|
||||
parallel: true
|
||||
|
||||
#
|
||||
# things to run in the 2nd CI container
|
||||
#
|
||||
- if [ $CIRCLE_NODE_INDEX == 1 ]; then npm run all test -- --package driver; fi:
|
||||
parallel: true
|
||||
|
||||
#
|
||||
# things to run in the 3rd CI container
|
||||
#
|
||||
- if [ $CIRCLE_NODE_INDEX == 2 ]; then npm run all test-e2e-once -- --package server; fi:
|
||||
parallel: true
|
||||
|
||||
# Example project E2E tests
|
||||
# Hanging now, so commented out
|
||||
# - if [ $CIRCLE_NODE_INDEX == 0 ]; then npm start -- --project ../example/; fi:
|
||||
# parallel: true
|
||||
|
||||
@@ -11,8 +11,7 @@ switch (args.exec) {
|
||||
require('dev/run')(args)
|
||||
break
|
||||
case 'install':
|
||||
//// TODO: do this through lib/cli.js?
|
||||
require('packages/core-download').install()
|
||||
require('./lib/download').install()
|
||||
break
|
||||
case undefined:
|
||||
throw new Error('Must pass --exec option')
|
||||
|
||||
@@ -17,11 +17,8 @@ const packageNameFromPath = (fullPath) => {
|
||||
.replace('packages/', '')
|
||||
}
|
||||
|
||||
const nonPackageDirs = ['docs/']
|
||||
|
||||
const getDirs = () => {
|
||||
return globAsync('packages/*/')
|
||||
.then((dirs) => dirs.concat(nonPackageDirs))
|
||||
.map((dir) => path.join(process.cwd(), dir).replace(/\/$/, ''))
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -98,10 +98,9 @@ node_sass:
|
||||
precision: 5
|
||||
sourceComments: false
|
||||
|
||||
## https://github.com/hexojs/hexo-generator-sitemap
|
||||
## https://github.com/ludoviclefevre/hexo-generator-seo-friendly-sitemap
|
||||
sitemap:
|
||||
path: sitemap.xml
|
||||
template: ./sitemap_template.xml
|
||||
|
||||
## https://github.com/mamboer/hexo-filter-cleanup
|
||||
hfc_useref:
|
||||
@@ -144,5 +143,6 @@ hfc_favicons:
|
||||
## Docs: https://hexo.io/docs/deployment.html
|
||||
deploy:
|
||||
type: git
|
||||
repo: https://github.com/cypress-io/cypress-documentation
|
||||
repo: git@github.com:cypress-io/cypress-monorepo
|
||||
branch: gh-pages
|
||||
message: '[skip ci] deploying docs'
|
||||
|
||||
@@ -27,7 +27,7 @@ describe "Documentation", ->
|
||||
cy
|
||||
.contains(".main-nav-link", "Guides")
|
||||
.should("have.attr", "href")
|
||||
.and("include", "/guides/welcome/guides.html")
|
||||
.and("include", "/guides/index.html")
|
||||
cy
|
||||
.contains(".main-nav-link", "API")
|
||||
.should("have.attr", "href")
|
||||
|
||||
+34
-4
@@ -4,7 +4,7 @@ const clean = require('gulp-clean')
|
||||
const runSequence = require('run-sequence')
|
||||
|
||||
const revisionOpts = {
|
||||
dontGlobal: ['.ico', 'sitemap.xml', 'logo.png'],
|
||||
dontGlobal: ['.ico', 'sitemap.xml', 'sitemap.xsl', 'logo.png'],
|
||||
dontRenameFile: ['.html', 'CNAME'],
|
||||
dontUpdateReference: ['.html'],
|
||||
dontSearchFile: ['.js'],
|
||||
@@ -17,6 +17,34 @@ function remove (folder) {
|
||||
.pipe(clean())
|
||||
}
|
||||
|
||||
function moveJSNodeModule (path) {
|
||||
return gulp
|
||||
.src(`./node_modules/${path}`)
|
||||
.pipe(gulp.dest('./themes/cypress/source/js'))
|
||||
}
|
||||
|
||||
function moveCSSNodeModule (path) {
|
||||
return gulp
|
||||
.src(`./node_modules/${path}`)
|
||||
.pipe(gulp.dest('./themes/cypress/source/css'))
|
||||
}
|
||||
|
||||
gulp.task('move:menu:spy:js', function () {
|
||||
return moveJSNodeModule('menuspy/dist/menuspy.js')
|
||||
})
|
||||
|
||||
gulp.task('move:scrolling:element:js', function () {
|
||||
return moveJSNodeModule('scrollingelement/scrollingelement.js')
|
||||
})
|
||||
|
||||
gulp.task('move:doc:search:js', function () {
|
||||
return moveJSNodeModule('docsearch.js/dist/cdn/docsearch.js')
|
||||
})
|
||||
|
||||
gulp.task('move:doc:search:css', function () {
|
||||
return moveCSSNodeModule('docsearch.js/dist/cdn/docsearch.css')
|
||||
})
|
||||
|
||||
gulp.task('revision', () => {
|
||||
return gulp
|
||||
.src('public/**')
|
||||
@@ -24,7 +52,7 @@ gulp.task('revision', () => {
|
||||
.pipe(gulp.dest('tmp'))
|
||||
})
|
||||
|
||||
gulp.task('copyTmpToPublic', () => {
|
||||
gulp.task('copy:tmp:to:public', () => {
|
||||
return gulp
|
||||
.src('tmp/**')
|
||||
.pipe(gulp.dest('public'))
|
||||
@@ -46,6 +74,8 @@ gulp.task('cname', () => {
|
||||
return gulp.src('CNAME').pipe(gulp.dest('public'))
|
||||
})
|
||||
|
||||
gulp.task('prep', (cb) => {
|
||||
runSequence('clean:js', 'revision', 'clean:public', 'copyTmpToPublic', 'clean:tmp', 'cname', cb)
|
||||
gulp.task('post:build', (cb) => {
|
||||
runSequence('copy:static:assets', 'clean:js', 'revision', 'clean:public', 'copy:tmp:to:public', 'clean:tmp', 'cname', cb)
|
||||
})
|
||||
|
||||
gulp.task('copy:static:assets', ['move:menu:spy:js', 'move:scrolling:element:js', 'move:doc:search:js', 'move:doc:search:css'])
|
||||
|
||||
+8
-3
@@ -6,9 +6,12 @@
|
||||
"version": "3.3.1"
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "npm run build",
|
||||
"prebuild": "npm run clean",
|
||||
"build": "hexo generate",
|
||||
"postbuild": "gulp post:build",
|
||||
"clean": "hexo clean",
|
||||
"clean-deps": "rm -rf node_modules",
|
||||
"clean-all": "npm run clean && npm run clean-deps",
|
||||
"convert": "node ./cy_scripts/convert.js",
|
||||
"deploy": "npm run build && hexo deploy",
|
||||
"build-prod": "hexo clean && hexo generate && gulp prep",
|
||||
@@ -28,18 +31,20 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"bluebird": "^3.5.0",
|
||||
"docsearch.js": "^2.3.3",
|
||||
"hexo": "3.3.1",
|
||||
"hexo-algoliasearch": "^0.2.1",
|
||||
"hexo-deployer-git": "^0.2.0",
|
||||
"hexo-generator-archive": "^0.1.4",
|
||||
"hexo-generator-category": "^0.1.3",
|
||||
"hexo-generator-index": "^0.2.0",
|
||||
"hexo-generator-sitemap": "^1.1.2",
|
||||
"hexo-generator-seo-friendly-sitemap": "0.0.20",
|
||||
"hexo-renderer-marked": "^0.2.10",
|
||||
"hexo-renderer-scss": "^1.0.2",
|
||||
"hexo-server": "^0.2.0",
|
||||
"lodash": "^4.17.4",
|
||||
"lunr": "^2.0.1",
|
||||
"menuspy": "^1.0.1"
|
||||
"menuspy": "1.0.1",
|
||||
"scrollingelement": "1.5.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
guides: /guides/welcome/guides.html
|
||||
guides: /guides/index.html
|
||||
api: /api/welcome/api.html
|
||||
faq: /faq.html
|
||||
ecosystem: /ecosystem.html
|
||||
ecosystem: /ecosystem/index.html
|
||||
faq: /faq/index.html
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
title: Frequently Asked Questions
|
||||
---
|
||||
|
||||
# General Questions
|
||||
|
||||
### What is Cypress?
|
||||
|
||||
Cypress is this thing that does this stuff.
|
||||
|
||||
### Why is this different?
|
||||
|
||||
This stuff has never been done before!
|
||||
|
||||
### Does Cypress use Selenium / Webdriver?
|
||||
|
||||
No way!
|
||||
|
||||
### What operating systems do you support?
|
||||
|
||||
All the really great ones.
|
||||
|
||||
### Will Cypress work in my CI provider?
|
||||
|
||||
Indubitably!
|
||||
|
||||
### What are good use cases for Cypress?
|
||||
|
||||
Testing the untestable.
|
||||
|
||||
### What are bad use cases for Cypress?
|
||||
|
||||
Testing the way you've always done it.
|
||||
|
||||
### How can I parallelize my runs?
|
||||
|
||||
Cloudy cloud clouder
|
||||
|
||||
### Is there code coverage?
|
||||
|
||||
Don't chase the dragon.
|
||||
|
||||
### What kind of tests do I write in Cypress?
|
||||
|
||||
The BEST kind!
|
||||
|
||||
### Are there driver bindings in my language?
|
||||
|
||||
I didn't understand the questions I heard.
|
||||
|
||||
### Does Cypress have an equivalent to Selenium IDE?
|
||||
|
||||
WIZARD MODE COMING SOON
|
||||
|
||||
# Using Cypress (potentially split this into Beginner / Advanced sections)
|
||||
### How do I wait for an element not to exist?
|
||||
### How do I do different things depending on what’s currently in the dom/url/cookies/localstore?
|
||||
### Can I run a single test or group of tests?
|
||||
### Can I test file uploading?
|
||||
### How do I test drag-n-drop?
|
||||
### How do I seed / reset my database?
|
||||
### How do I test anchor links that open in a new tab?
|
||||
### Should I start my webserver from within Cypress?
|
||||
### Can I make an assertion on my application’s console.logs?
|
||||
### How do I make conditional based assertions / control flow?
|
||||
# Dashboard
|
||||
### What is the Dashboard?
|
||||
### How much does it cost?
|
||||
### What does Cypress record?
|
||||
# Company
|
||||
### Who’s behind Cypress?
|
||||
### Are you hiring?
|
||||
@@ -0,0 +1,230 @@
|
||||
---
|
||||
layout: plain
|
||||
title: FAQ
|
||||
comments: false
|
||||
containerClass: faq
|
||||
---
|
||||
|
||||
# General Questions
|
||||
|
||||
## What is Cypress?
|
||||
|
||||
|
||||
|
||||
## Hasn’t this been done before?
|
||||
|
||||
|
||||
## Is Cypress free?
|
||||
|
||||
|
||||
|
||||
## What operating systems do you support?
|
||||
|
||||
|
||||
|
||||
## Do you support native mobile apps?
|
||||
|
||||
|
||||
|
||||
## Do you support X language or X framework?
|
||||
|
||||
|
||||
|
||||
## Will Cypress work in my CI provider?
|
||||
|
||||
|
||||
|
||||
## What are good use cases for Cypress?
|
||||
|
||||
|
||||
## What are bad use cases for Cypress?
|
||||
|
||||
|
||||
## Is there code coverage?
|
||||
|
||||
[#346](https://github.com/cypress-io/cypress/issues/346)
|
||||
|
||||
## What kind of tests do I write in Cypress?
|
||||
|
||||
|
||||
## Does Cypress use Selenium / Webdriver?
|
||||
|
||||
|
||||
|
||||
## Are there driver bindings in my language?
|
||||
|
||||
|
||||
|
||||
## Does Cypress have an equivalent to Selenium IDE?
|
||||
|
||||
|
||||
|
||||
## Is Cypress open source?
|
||||
|
||||
|
||||
|
||||
## How can I contribute to Cypress?
|
||||
|
||||
|
||||
## I found a bug! What do I do?
|
||||
|
||||
|
||||
|
||||
# Using Cypress (potentially split this into Beginner / Advanced sections)
|
||||
|
||||
## How do I wait for an element not to exist?
|
||||
|
||||
|
||||
|
||||
## How do I do different things depending on what’s currently in the dom/url/cookies/localstore?
|
||||
|
||||
|
||||
## How can I parallelize my runs?
|
||||
|
||||
[#64](https://github.com/cypress-io/cypress/issues/64)
|
||||
|
||||
|
||||
|
||||
## Can I run a single test or group of tests?
|
||||
|
||||
[#236](https://github.com/cypress-io/cypress/issues/263)
|
||||
|
||||
## How do I test uploading a file?
|
||||
|
||||
[#170](https://github.com/cypress-io/cypress/issues/170)
|
||||
|
||||
## What is the projectId for?
|
||||
|
||||
|
||||
|
||||
## How do I get the native DOM reference of an element found using Cypress?
|
||||
|
||||
|
||||
|
||||
## How do I make Cypress wait for an XHR request?
|
||||
|
||||
|
||||
|
||||
## How do I wait for multiple XHR requests to the same url?
|
||||
|
||||
|
||||
|
||||
## How do I test drag-n-drop?
|
||||
|
||||
|
||||
|
||||
## How do I seed / reset my database?
|
||||
|
||||
|
||||
|
||||
## How do I pass data to my webserver from Cypress?
|
||||
|
||||
|
||||
|
||||
## How do I content inside an iframe?
|
||||
|
||||
[#136](https://github.com/cypress-io/cypress/issues/136)
|
||||
|
||||
## How do I preserve cookies/localstorage in between my tests?
|
||||
|
||||
[#461](https://github.com/cypress-io/cypress/issues/461)
|
||||
|
||||
## Some of my elements animate in, how do I work around that?
|
||||
|
||||
|
||||
|
||||
## Can I test anchor links that open in a new tab?
|
||||
|
||||
|
||||
|
||||
## Should I start my webserver from within Cypress?
|
||||
|
||||
|
||||
|
||||
## Can I make an assertion on my application’s console.logs?
|
||||
|
||||
|
||||
|
||||
## How do I run my tests in another browser?
|
||||
|
||||
|
||||
|
||||
## Where do I get the key to run my tests in CI?
|
||||
|
||||
|
||||
|
||||
## Can I create more than one key for CI?
|
||||
|
||||
|
||||
|
||||
## I have an app that needs to be tested across multiple user sessions, like a chat app across 2 browsers. How do I test that?
|
||||
|
||||
|
||||
|
||||
## I want to test clicking a link that navigates, how do I wait and check the resulting location url?
|
||||
|
||||
|
||||
|
||||
## Is there a way to watch for an xhr request and assert that the response code came back a certain way?
|
||||
|
||||
|
||||
|
||||
## I’m running a lot of tests that appear to slow down as they run, is there a way to fix this?
|
||||
|
||||
|
||||
|
||||
## How do I make conditional based assertions / control flow?
|
||||
|
||||
|
||||
# Dashboard
|
||||
|
||||
## What is the Dashboard?
|
||||
|
||||
|
||||
|
||||
## How much does it cost?
|
||||
|
||||
|
||||
|
||||
## What does Cypress record?
|
||||
|
||||
|
||||
|
||||
## How many recordings can I store?
|
||||
|
||||
|
||||
|
||||
## Can't I just record my app running, without the Cypress runner?
|
||||
|
||||
|
||||
|
||||
## Can I see the mouse movements in my recorded video?
|
||||
|
||||
|
||||
|
||||
## Is there a way to see console logs or application errors in a recorded run?
|
||||
|
||||
|
||||
|
||||
## Is it possible to transfer a project to an organization I'm not a member of?
|
||||
|
||||
|
||||
|
||||
## Why are my tests displaying a “still running”?
|
||||
|
||||
|
||||
|
||||
## Is there any way to remove a run and the data from the Dashboard?
|
||||
|
||||
|
||||
|
||||
## How secure is storing my test runs (videos and screenshots) on your servers?
|
||||
|
||||
|
||||
# Company
|
||||
|
||||
## Who’s behind Cypress?
|
||||
|
||||
|
||||
|
||||
## Are you hiring?
|
||||
+4
-21
@@ -5,26 +5,9 @@
|
||||
{{ js('js/menuspy') }}
|
||||
{{ js('js/toc') }}
|
||||
{{ js('js/mobile_nav') }}
|
||||
<!-- endbuild -->
|
||||
<script src="https://cdn.jsdelivr.net/retinajs/1.3.0/retina.min.js" async></script>
|
||||
|
||||
<!-- Algolia -->
|
||||
{% if config.algolia[page.lang] %}
|
||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
document.getElementById('search-input-wrap').classList.add('on');
|
||||
docsearch({
|
||||
apiKey: '{{ config.algolia[page.lang].api_key }}',
|
||||
indexName: '{{ config.algolia[page.lang].index_name }}',
|
||||
inputSelector: '#search-input',
|
||||
algoliaOptions: {
|
||||
// See https://www.algolia.com/doc/api-client/javascript/parameters/#overview
|
||||
// For full list of options
|
||||
},
|
||||
autocompleteOptions: {
|
||||
// See https://github.com/algolia/autocomplete.js#options
|
||||
// For full list of options
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<!-- Algolia -->
|
||||
{{ js('js/docsearch') }}
|
||||
{{ js('js/docsearch-config') }}
|
||||
{% endif %}
|
||||
<!-- endbuild -->
|
||||
|
||||
+1
-2
@@ -21,10 +21,9 @@
|
||||
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/docsearch.js/1/docsearch.min.css">
|
||||
|
||||
<!-- CSS -->
|
||||
<!-- build:css build/css/cypress.css -->
|
||||
{{ css('css/docsearch') }}
|
||||
{{ css('css/cypress') }}
|
||||
<!-- endbuild -->
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
.faq {
|
||||
width: 750px;
|
||||
margin: 0 auto 50px;
|
||||
|
||||
|
||||
h1, h2, p {
|
||||
font-family: $font-title;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2.5em;
|
||||
line-height: 1em;
|
||||
font-weight: 800;
|
||||
margin: 2em 0 1em;
|
||||
|
||||
&:first-of-type {
|
||||
margin-top: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.4em;
|
||||
line-height: 1.6em;
|
||||
margin: 1.5em 0 0.5em;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 1em;
|
||||
}
|
||||
}
|
||||
+1
@@ -4,6 +4,7 @@
|
||||
@import "_partial/header";
|
||||
@import "_partial/search";
|
||||
@import "_partial/index";
|
||||
@import "_partial/faq";
|
||||
@import "_partial/sidebar";
|
||||
@import "_partial/toc";
|
||||
@import "_partial/page";
|
||||
|
||||
+517
File diff suppressed because one or more lines are too long
@@ -0,0 +1,14 @@
|
||||
document.getElementById('search-input-wrap').classList.add('on');
|
||||
docsearch({
|
||||
apiKey: '{{ config.algolia[page.lang].api_key }}',
|
||||
indexName: '{{ config.algolia[page.lang].index_name }}',
|
||||
inputSelector: '#search-input',
|
||||
algoliaOptions: {
|
||||
// See https://www.algolia.com/doc/api-client/javascript/parameters/#overview
|
||||
// For full list of options
|
||||
},
|
||||
autocompleteOptions: {
|
||||
// See https://github.com/algolia/autocomplete.js#options
|
||||
// For full list of options
|
||||
}
|
||||
});
|
||||
+9800
File diff suppressed because it is too large
Load Diff
+173
-173
@@ -1,173 +1,173 @@
|
||||
/*! MenuSpy v1.0.0 (Nov 29 2016) - http://leocs.me/menuspy/ - Copyright (c) 2016 Leonardo Santos; MIT License */
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
||||
typeof define === 'function' && define.amd ? define(factory) :
|
||||
(global.MenuSpy = factory());
|
||||
}(this, (function () { 'use strict';
|
||||
|
||||
var utils = {
|
||||
extend: function extend(a, b) {
|
||||
for (var key in b) {
|
||||
if (b.hasOwnProperty(key)) {
|
||||
a[key] = b[key];
|
||||
}
|
||||
}
|
||||
|
||||
return a;
|
||||
},
|
||||
|
||||
offset: function offset(el) {
|
||||
var rect = el.getBoundingClientRect();
|
||||
|
||||
return {
|
||||
top: rect.top + document.body.scrollTop,
|
||||
left: rect.left + document.body.scrollLeft
|
||||
};
|
||||
},
|
||||
|
||||
scrollTop: function scrollTop() {
|
||||
return window.pageYOffset || document.documentElement.scrollTop;
|
||||
},
|
||||
|
||||
addClass: function addClass(el, className) {
|
||||
if (el.classList) {
|
||||
el.classList.add(className);
|
||||
} else {
|
||||
var classes = el.className.split(' ');
|
||||
var existingIndex = classes.indexOf(className);
|
||||
|
||||
if (existingIndex === -1) {
|
||||
classes.push(className);
|
||||
}
|
||||
|
||||
el.className = classes.join(' ');
|
||||
}
|
||||
},
|
||||
|
||||
removeClass: function removeClass(el, className) {
|
||||
if (el.classList) {
|
||||
el.classList.remove(className);
|
||||
} else {
|
||||
el.className = el.className.replace(new RegExp(("(^|\\b)" + (className.split(' ').join('|')) + "(\\b|$)"), 'gi'), ' ');
|
||||
}
|
||||
},
|
||||
|
||||
debounce: function debounce(fn, delay) {
|
||||
var timeout = null;
|
||||
return function() {
|
||||
var args = arguments;
|
||||
var context = this;
|
||||
if (!timeout) {
|
||||
timeout = setTimeout(function () {
|
||||
timeout = 0;
|
||||
return fn.apply(context, args);
|
||||
}, delay);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
var MenuSpy = function MenuSpy(element, options) {
|
||||
var this$1 = this;
|
||||
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
var defaults = {
|
||||
menuItemSelector: 'a[href^="#"]',
|
||||
activeClass : 'active',
|
||||
threshold : 15,
|
||||
hashTimeout : 600,
|
||||
callback : null
|
||||
};
|
||||
|
||||
this.element = element;
|
||||
this.options = utils.extend(defaults, options);
|
||||
|
||||
this.assignValues();
|
||||
window.addEventListener('resize', utils.debounce(function () { return this$1.assignValues(); }));
|
||||
|
||||
this.debouncedHashFn = utils.debounce(function () {
|
||||
if (history.replaceState) {
|
||||
history.replaceState(null, null, ("#" + (this$1.lastId)));
|
||||
} else {
|
||||
var st = utils.scrollTop();
|
||||
window.location.hash = this$1.lastId;
|
||||
window.scrollTo(0, st);
|
||||
}
|
||||
}, this.options.hashTimeout);
|
||||
|
||||
this.cacheItems();
|
||||
this.scrollFn();
|
||||
};
|
||||
|
||||
MenuSpy.prototype.assignValues = function assignValues () {
|
||||
this.currScrollTop = 0;
|
||||
this.lastId = '';
|
||||
this.menuHeight = this.element.offsetHeight + this.options.threshold;
|
||||
this.menuItems = [].slice.call(this.element.querySelectorAll(this.options.menuItemSelector));
|
||||
};
|
||||
|
||||
MenuSpy.prototype.cacheItems = function cacheItems () {
|
||||
this.scrollItems = this.menuItems.map(function (a) {
|
||||
var elm = document.querySelector(a.getAttribute('href'));
|
||||
if (elm) {
|
||||
var offset = utils.offset(elm).top;
|
||||
return { elm: elm, offset: offset };
|
||||
} else {
|
||||
console.warn('MenuSpy warning: %s not found on page.', a.href);
|
||||
}
|
||||
});
|
||||
this.scrollItems = this.scrollItems.filter( Boolean );
|
||||
};
|
||||
|
||||
MenuSpy.prototype.tick = function tick () {
|
||||
var fromTop = this.currScrollTop + this.menuHeight;
|
||||
var inViewElms = this.scrollItems
|
||||
.filter(function (item) { return item.offset < fromTop; })
|
||||
.map(function (item) { return item.elm; });
|
||||
|
||||
this.activateItem(inViewElms.pop());
|
||||
};
|
||||
|
||||
MenuSpy.prototype.activateItem = function activateItem (inViewElm) {
|
||||
var this$1 = this;
|
||||
|
||||
var id = inViewElm ? inViewElm.id : '';
|
||||
var activeClass = this.options.activeClass;
|
||||
var callback = this.options.callback;
|
||||
|
||||
if (this.lastId !== id) {
|
||||
this.lastId = id;
|
||||
|
||||
this.menuItems.forEach(function (item) {
|
||||
utils.removeClass(item.parentNode, activeClass);
|
||||
|
||||
if (item.getAttribute('href') === ("#" + id)) {
|
||||
utils.addClass(item.parentNode, activeClass);
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback.call(this$1, item, inViewElm);
|
||||
}
|
||||
|
||||
this$1.debouncedHashFn();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
MenuSpy.prototype.scrollFn = function scrollFn () {
|
||||
var st = utils.scrollTop();
|
||||
|
||||
if (this.currScrollTop !== st) {
|
||||
this.currScrollTop = st;
|
||||
this.tick();
|
||||
}
|
||||
|
||||
window.requestAnimationFrame(this.scrollFn.bind(this));
|
||||
};
|
||||
|
||||
return MenuSpy;
|
||||
|
||||
})));
|
||||
/*! MenuSpy v1.0.0 (Nov 29 2016) - http://leocs.me/menuspy/ - Copyright (c) 2016 Leonardo Santos; MIT License */
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
||||
typeof define === 'function' && define.amd ? define(factory) :
|
||||
(global.MenuSpy = factory());
|
||||
}(this, (function () { 'use strict';
|
||||
|
||||
var utils = {
|
||||
extend: function extend(a, b) {
|
||||
for (var key in b) {
|
||||
if (b.hasOwnProperty(key)) {
|
||||
a[key] = b[key];
|
||||
}
|
||||
}
|
||||
|
||||
return a;
|
||||
},
|
||||
|
||||
offset: function offset(el) {
|
||||
var rect = el.getBoundingClientRect();
|
||||
|
||||
return {
|
||||
top: rect.top + document.body.scrollTop,
|
||||
left: rect.left + document.body.scrollLeft
|
||||
};
|
||||
},
|
||||
|
||||
scrollTop: function scrollTop() {
|
||||
return window.pageYOffset || document.documentElement.scrollTop;
|
||||
},
|
||||
|
||||
addClass: function addClass(el, className) {
|
||||
if (el.classList) {
|
||||
el.classList.add(className);
|
||||
} else {
|
||||
var classes = el.className.split(' ');
|
||||
var existingIndex = classes.indexOf(className);
|
||||
|
||||
if (existingIndex === -1) {
|
||||
classes.push(className);
|
||||
}
|
||||
|
||||
el.className = classes.join(' ');
|
||||
}
|
||||
},
|
||||
|
||||
removeClass: function removeClass(el, className) {
|
||||
if (el.classList) {
|
||||
el.classList.remove(className);
|
||||
} else {
|
||||
el.className = el.className.replace(new RegExp(("(^|\\b)" + (className.split(' ').join('|')) + "(\\b|$)"), 'gi'), ' ');
|
||||
}
|
||||
},
|
||||
|
||||
debounce: function debounce(fn, delay) {
|
||||
var timeout = null;
|
||||
return function() {
|
||||
var args = arguments;
|
||||
var context = this;
|
||||
if (!timeout) {
|
||||
timeout = setTimeout(function () {
|
||||
timeout = 0;
|
||||
return fn.apply(context, args);
|
||||
}, delay);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
var MenuSpy = function MenuSpy(element, options) {
|
||||
var this$1 = this;
|
||||
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
var defaults = {
|
||||
menuItemSelector: 'a[href^="#"]',
|
||||
activeClass : 'active',
|
||||
threshold : 15,
|
||||
hashTimeout : 600,
|
||||
callback : null
|
||||
};
|
||||
|
||||
this.element = element;
|
||||
this.options = utils.extend(defaults, options);
|
||||
|
||||
this.assignValues();
|
||||
window.addEventListener('resize', utils.debounce(function () { return this$1.assignValues(); }));
|
||||
|
||||
this.debouncedHashFn = utils.debounce(function () {
|
||||
if (history.replaceState) {
|
||||
history.replaceState(null, null, ("#" + (this$1.lastId)));
|
||||
} else {
|
||||
var st = utils.scrollTop();
|
||||
window.location.hash = this$1.lastId;
|
||||
window.scrollTo(0, st);
|
||||
}
|
||||
}, this.options.hashTimeout);
|
||||
|
||||
this.cacheItems();
|
||||
this.scrollFn();
|
||||
};
|
||||
|
||||
MenuSpy.prototype.assignValues = function assignValues () {
|
||||
this.currScrollTop = 0;
|
||||
this.lastId = '';
|
||||
this.menuHeight = this.element.offsetHeight + this.options.threshold;
|
||||
this.menuItems = [].slice.call(this.element.querySelectorAll(this.options.menuItemSelector));
|
||||
};
|
||||
|
||||
MenuSpy.prototype.cacheItems = function cacheItems () {
|
||||
this.scrollItems = this.menuItems.map(function (a) {
|
||||
var elm = document.querySelector(a.getAttribute('href'));
|
||||
if (elm) {
|
||||
var offset = utils.offset(elm).top;
|
||||
return { elm: elm, offset: offset };
|
||||
} else {
|
||||
console.warn('MenuSpy warning: %s not found on page.', a.href);
|
||||
}
|
||||
});
|
||||
this.scrollItems = this.scrollItems.filter( Boolean );
|
||||
};
|
||||
|
||||
MenuSpy.prototype.tick = function tick () {
|
||||
var fromTop = this.currScrollTop + this.menuHeight;
|
||||
var inViewElms = this.scrollItems
|
||||
.filter(function (item) { return item.offset < fromTop; })
|
||||
.map(function (item) { return item.elm; });
|
||||
|
||||
this.activateItem(inViewElms.pop());
|
||||
};
|
||||
|
||||
MenuSpy.prototype.activateItem = function activateItem (inViewElm) {
|
||||
var this$1 = this;
|
||||
|
||||
var id = inViewElm ? inViewElm.id : '';
|
||||
var activeClass = this.options.activeClass;
|
||||
var callback = this.options.callback;
|
||||
|
||||
if (this.lastId !== id) {
|
||||
this.lastId = id;
|
||||
|
||||
this.menuItems.forEach(function (item) {
|
||||
utils.removeClass(item.parentNode, activeClass);
|
||||
|
||||
if (item.getAttribute('href') === ("#" + id)) {
|
||||
utils.addClass(item.parentNode, activeClass);
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback.call(this$1, item, inViewElm);
|
||||
}
|
||||
|
||||
this$1.debouncedHashFn();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
MenuSpy.prototype.scrollFn = function scrollFn () {
|
||||
var st = utils.scrollTop();
|
||||
|
||||
if (this.currScrollTop !== st) {
|
||||
this.currScrollTop = st;
|
||||
this.tick();
|
||||
}
|
||||
|
||||
window.requestAnimationFrame(this.scrollFn.bind(this));
|
||||
};
|
||||
|
||||
return MenuSpy;
|
||||
|
||||
})));
|
||||
+7
-12
@@ -6,19 +6,14 @@
|
||||
"cypress": "bin/cypress"
|
||||
},
|
||||
"scripts": {
|
||||
"install-app": "node cli.js --exec install",
|
||||
"postinstall": "npm run all install && npm run all build-dev",
|
||||
"deploy:docs": "npm run all deploy -- --package docs",
|
||||
"start": "node start.js",
|
||||
"watch-dev": "npm run all watch-dev",
|
||||
"test": "mocha --watch",
|
||||
"test-once": "mocha",
|
||||
"test-all": "npm run all test -- --serial",
|
||||
"test-all-once": "npm run all test-once -- --serial",
|
||||
"test-all-unit-once": "npm run all test-unit-once -- --serial",
|
||||
"test-all-integration-once": "npm run all test-integration-once -- --serial",
|
||||
"test-all-e2e-once": "npm run all test-e2e-once -- --serial",
|
||||
"all": "node cli.js --exec run"
|
||||
"watch": "npm run all watch",
|
||||
"build": "npm run all build",
|
||||
"all": "node cli.js --exec run",
|
||||
"test": "echo 'This runs just the CLI tests' && mocha",
|
||||
"test-watch": "mocha --watch",
|
||||
"test-e2e": "blah",
|
||||
"postinstall": "npm run all install && npm run build"
|
||||
},
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -4,16 +4,15 @@
|
||||
"description": "Desktop GUI for managing Cypress projects.",
|
||||
"main": "lib/gui.js",
|
||||
"scripts": {
|
||||
"build-dev": "zunder build-dev",
|
||||
"build": "zunder build-dev",
|
||||
"build-prod": "node ./scripts/build-prod.js",
|
||||
"run-prod": "npm run build-prod && npm run server",
|
||||
"watch": "zunder watch",
|
||||
"server": "zunder serve-prod --port 8000",
|
||||
"watch-dev": "zunder watch",
|
||||
"clean": "zunder clean",
|
||||
"clean-deps": "rm -rf node_modules",
|
||||
"clean-all": "npm run clean && npm run clean-deps",
|
||||
"lint": "eslint --fix lib/*.js src/*.js* src/**/*.js*",
|
||||
"test": "npm run build-dev",
|
||||
"test": "npm run build",
|
||||
"pretest": "npm run lint"
|
||||
},
|
||||
"repository": {
|
||||
|
||||
@@ -155,7 +155,7 @@ gulp.task "server", -> require("./server/server.coffee")
|
||||
gulp.task "ensure:dist:dir", ->
|
||||
fs.ensureDirAsync(path.resolve("./dist-test"))
|
||||
|
||||
gulp.task "test", ["ensure:dist:dir"], ->
|
||||
gulp.task "test:watch", ["ensure:dist:dir"], ->
|
||||
watchSpecHelper = bundleJs(specHelperOptions)
|
||||
watchIndex = bundleJs(specIndexOptions)
|
||||
watchRunner = bundleJs(specRunnerOptions)
|
||||
@@ -167,7 +167,7 @@ gulp.task "test", ["ensure:dist:dir"], ->
|
||||
|
||||
return watchSpecHelper.process
|
||||
|
||||
gulp.task "test:once", ["ensure:dist:dir"], ->
|
||||
gulp.task "test", ["ensure:dist:dir"], ->
|
||||
buildSpecHelper = bundleJs(specHelperOptions, false)
|
||||
buildIndex = bundleJs(specIndexOptions, false)
|
||||
buildRunner = bundleJs(specRunnerOptions, false)
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"build-dev": "gulp build",
|
||||
"build": "gulp build",
|
||||
"watch": "gulp watch",
|
||||
"clean-deps": "rm -rf node_modules",
|
||||
"test": "gulp test:once",
|
||||
"test-watch": "gulp test",
|
||||
"watch-dev": "gulp watch"
|
||||
"test": "gulp test",
|
||||
"test-watch": "gulp test:watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cypress/bower-kendo-ui": "0.0.2",
|
||||
|
||||
@@ -29,9 +29,6 @@ args = [
|
||||
"--disable-new-avatar-menu"
|
||||
"--allow-insecure-localhost"
|
||||
"--reduce-security-for-testing"
|
||||
## FIXME: theme doesn't seem to work
|
||||
"--load-extension=#{themeDir}"
|
||||
"--user-data-dir=#{profileDir}"
|
||||
|
||||
## the following come frome chromedriver
|
||||
## https://code.google.com/p/chromium/codesearch#chromium/src/chrome/test/chromedriver/chrome_launcher.cc&sq=package:chromium&l=70
|
||||
@@ -46,6 +43,9 @@ args = [
|
||||
"--disable-client-side-phishing-detection"
|
||||
"--disable-component-update"
|
||||
"--disable-default-apps"
|
||||
|
||||
"--load-extension=#{themeDir}"
|
||||
"--user-data-dir=#{profileDir}"
|
||||
]
|
||||
|
||||
module.exports = {
|
||||
@@ -57,8 +57,9 @@ module.exports = {
|
||||
launch.launch(browser, url, args)
|
||||
.then (spawnedBrowser) ->
|
||||
{
|
||||
stop: (cb) ->
|
||||
spawnedBrowser.on("close", cb)
|
||||
spawnedBrowser.kill()
|
||||
stop: ->
|
||||
new Promise (resolve) ->
|
||||
spawnedBrowser.once("exit", resolve)
|
||||
spawnedBrowser.kill()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ module.exports = class Runner
|
||||
@_errors = []
|
||||
@_localBus = new EventEmitter()
|
||||
@_runnerBus = new EventEmitter()
|
||||
@_browserInstance = { stop: -> Promise.resolve() }
|
||||
|
||||
process.on "SIGINT", =>
|
||||
@_stopBrowser().then ->
|
||||
@@ -82,14 +83,19 @@ module.exports = class Runner
|
||||
@_runnerBus.emit(event, info, err)
|
||||
|
||||
runAllSpecsOnce: (specPaths) ->
|
||||
@_start().then =>
|
||||
@_start()
|
||||
.then =>
|
||||
new Promise (resolve, reject) =>
|
||||
current = 0
|
||||
timeouts = []
|
||||
|
||||
next = =>
|
||||
current++
|
||||
@run(specPaths[current])
|
||||
@_stopBrowser()
|
||||
.then =>
|
||||
@_launchBrowser()
|
||||
.then =>
|
||||
@run(specPaths[current])
|
||||
|
||||
finish = (event, info, err) =>
|
||||
@_runnerBus.emit(event, info, err)
|
||||
@@ -100,9 +106,6 @@ module.exports = class Runner
|
||||
@_reporter = new @_Reporter(@_runnerBus)
|
||||
@_runnerBus.emit("start")
|
||||
|
||||
@_localBus.once "client:connected", =>
|
||||
@run(specPaths[current])
|
||||
|
||||
@_localBus.on "test:event", (event, info, err) =>
|
||||
if event is "end"
|
||||
if current is (specPaths.length - 1)
|
||||
@@ -113,10 +116,18 @@ module.exports = class Runner
|
||||
else if event isnt "start"
|
||||
@_runnerBus.emit(event, info, err)
|
||||
|
||||
@_localBus.on "timeout", ->
|
||||
timeouts.push(specPaths[current])
|
||||
@_localBus.on "timeout", (test) ->
|
||||
timeouts.push({ path: specPaths[current], test })
|
||||
next()
|
||||
|
||||
@run(specPaths[current])
|
||||
.tap ({ timeouts }) =>
|
||||
if timeouts.length
|
||||
logWarning("The following spec(s) timed out:")
|
||||
console.log()
|
||||
for spec in timeouts
|
||||
@_logTest(spec.test, spec.path)
|
||||
|
||||
run: (specPath) ->
|
||||
specPath = specPath
|
||||
.replace(path.join(__dirname, "../.."), "specs/")
|
||||
@@ -148,13 +159,16 @@ module.exports = class Runner
|
||||
theBrowser = getArg("browser") or "chrome"
|
||||
url = "http://localhost:#{@_config.port}?reporter=socket"
|
||||
|
||||
browser.launch(theBrowser, url)
|
||||
.then (instance) =>
|
||||
@_browserInstance = instance
|
||||
.catch (err) =>
|
||||
logError("Error attempting to launch browser:")
|
||||
logError(err)
|
||||
throw err
|
||||
new Promise (resolve, reject) =>
|
||||
@_localBus.once "client:connected", resolve
|
||||
|
||||
browser.launch(theBrowser, url)
|
||||
.then (instance) =>
|
||||
@_browserInstance = instance
|
||||
.catch (err) =>
|
||||
logError("Error attempting to launch browser:")
|
||||
logError(err)
|
||||
reject(err)
|
||||
|
||||
_onReport: ({ tests }) ->
|
||||
for test in tests
|
||||
@@ -173,27 +187,33 @@ module.exports = class Runner
|
||||
"#{info.parentTitle} #{info.title}"
|
||||
else
|
||||
info.title
|
||||
|
||||
if event is "test"
|
||||
@_lastTest = { event, info, err }
|
||||
|
||||
@_localBus.emit("test:event", event, info, err)
|
||||
|
||||
_logTest: ({ info, err }, path) ->
|
||||
logWarning("Spec:", path) if path
|
||||
logWarning("Test: #{info.fullTitle()}")
|
||||
logWarning("Error: #{err}") if err
|
||||
|
||||
_onTimeout: ->
|
||||
console.log()
|
||||
logError("Tests timed out")
|
||||
logError("Test timed out")
|
||||
console.log()
|
||||
if @_lastTest
|
||||
@_logTest(@_lastTest)
|
||||
if @_errors.length
|
||||
logWarning("The following errors were captured:")
|
||||
else
|
||||
logError("No errors were captured")
|
||||
console.log()
|
||||
logWarning("The following other errors were captured:")
|
||||
for error in @_errors
|
||||
console.log()
|
||||
logError(error.stack or error)
|
||||
@_localBus.emit("timeout")
|
||||
@_localBus.emit("timeout", @_lastTest)
|
||||
|
||||
_stopBrowser: ->
|
||||
if not @_browserInstance
|
||||
return Promise.resolve()
|
||||
|
||||
new Promise (resolve) =>
|
||||
@_browserInstance.stop(resolve)
|
||||
@_browserInstance.stop()
|
||||
.timeout(10000)
|
||||
.catch Promise.TimeoutError, ->
|
||||
logWarning("Timed out trying to stop browser")
|
||||
|
||||
@@ -44,6 +44,12 @@ getAllSpecs = (allSpecs = true) ->
|
||||
_.map specs, (spec) ->
|
||||
removeExtension(spec.replace("../..", "specs"))
|
||||
|
||||
## specify which files to run
|
||||
# [
|
||||
# "specs/unit/cy/commands/agents_spec"
|
||||
# "specs/unit/cy/commands/assertions_spec"
|
||||
# ]
|
||||
|
||||
getSpec = (spec) ->
|
||||
spec = "#{removeExtension(spec)}.coffee"
|
||||
file = fs.readFileSync(path.join(__dirname, "../..", spec), "utf8")
|
||||
@@ -69,6 +75,9 @@ app.get "/specs/*", (req, res) ->
|
||||
else
|
||||
res.render(path.join(__dirname, "views/spec.html"), {
|
||||
specs: getSpecPath(req.path)
|
||||
env: JSON.stringify({
|
||||
isCi: !!process.env.CI
|
||||
})
|
||||
})
|
||||
|
||||
app.get "/timeout", (req, res) ->
|
||||
@@ -169,9 +178,5 @@ module.exports = {
|
||||
.runAllSpecsOnce(getAllSpecs(false))
|
||||
.then ({ stats, timeouts }) ->
|
||||
code = if stats.failures or timeouts.length then 1 else 0
|
||||
if timeouts.length
|
||||
console.error("The following spec(s) timed out:")
|
||||
console.log()
|
||||
console.error(spec) for spec in timeouts
|
||||
process.exit(code)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Blank</title>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -14,6 +14,9 @@
|
||||
<a id="terminal-reporter" href="?reporter=socket">Terminal Reporter</a>
|
||||
</p>
|
||||
<div id="mocha"></div>
|
||||
<script>
|
||||
window.env = {{{env}}}
|
||||
</script>
|
||||
<script src="/dist-test/spec_helper.js"></script>
|
||||
{{#each specs}}
|
||||
<script src="/{{this}}.js"></script>
|
||||
|
||||
@@ -30,6 +30,18 @@ before ->
|
||||
c = Cypress ? @Cypress
|
||||
c.off("fail")
|
||||
|
||||
@assertWindowIsInFocus = (cb) ->
|
||||
return cb() if document.hasFocus()
|
||||
|
||||
ct = @test or @currentTest
|
||||
|
||||
if window.env.isCi
|
||||
ct.callback(
|
||||
new Error("Test requires the browser window be in focus, but it was not")
|
||||
)
|
||||
else
|
||||
ct.skip()
|
||||
|
||||
# sinon.format = -> ""
|
||||
@sandbox = s = sinon.sandbox.create()
|
||||
@sandbox.useFakeTimers = ->
|
||||
@@ -211,6 +223,9 @@ window.enterCommandTestingMode = (fixture = "dom", options = {}) ->
|
||||
## since we bypass our Runner instance
|
||||
@Cypress.on "fail", (err) ->
|
||||
console.error(err.stack)
|
||||
## bubble error up to mocha
|
||||
if ct
|
||||
ct.callback(err)
|
||||
|
||||
## if we've changed the src by navigating
|
||||
## away (aka cy.visit(...)) then we need
|
||||
|
||||
@@ -440,7 +440,8 @@ describe "$Cypress.Cy Miscellaneous Commands", ->
|
||||
|
||||
@cy.get("button:first").ttrigger("mouseover", "foo")
|
||||
|
||||
it "throws when element animation exceeds timeout", (done) ->
|
||||
## FIXME: needs focus
|
||||
it.skip "throws when element animation exceeds timeout", (done) ->
|
||||
@cy._timeout(100)
|
||||
|
||||
mouseovers = 0
|
||||
|
||||
@@ -540,7 +540,7 @@ describe "$Cypress.Cy Scrolling Commands", ->
|
||||
|
||||
@cy.get("button").scrollIntoView()
|
||||
|
||||
describe "argument errors", ->
|
||||
context "argument errors", ->
|
||||
it "throws if arg passed as non-object", (done) ->
|
||||
@cy.on "fail", (err) =>
|
||||
expect(err.message).to.include "cy.scrollIntoView() can only be called with an options object. Your argument was: foo"
|
||||
|
||||
@@ -87,22 +87,24 @@ describe "$Cypress.Cy Text Commands", ->
|
||||
|
||||
@cy.get(":text:first").type("foo{enter}")
|
||||
|
||||
it "waits until element stops animating", (done) ->
|
||||
retries = []
|
||||
input = $("<input class='slidein' />")
|
||||
input.css("animation-duration", ".3s")
|
||||
## FIXME: flakiness due to animation events
|
||||
it.skip "waits until element stops animating", (done) ->
|
||||
@assertWindowIsInFocus =>
|
||||
retries = []
|
||||
input = $("<input class='slidein' />")
|
||||
input.css("animation-duration", ".3s")
|
||||
|
||||
@cy.on "retry", (obj) ->
|
||||
## this verifies the input has not been typed into
|
||||
expect(input).to.have.value("")
|
||||
retries.push(obj)
|
||||
@cy.on "retry", (obj) ->
|
||||
## this verifies the input has not been typed into
|
||||
expect(input).to.have.value("")
|
||||
retries.push(obj)
|
||||
|
||||
input.on "animationstart", =>
|
||||
@cy.get(".slidein").type("foo").then ->
|
||||
expect(retries.length).to.be.gt(10)
|
||||
done()
|
||||
input.on "animationstart", =>
|
||||
@cy.get(".slidein").type("foo").then ->
|
||||
expect(retries.length).to.be.gt(10)
|
||||
done()
|
||||
|
||||
@cy.$$("#animation-container").append(input)
|
||||
@cy.$$("#animation-container").append(input)
|
||||
|
||||
it "does not throw when waiting for animations is disabled", ->
|
||||
@sandbox.stub(@Cypress, "config").withArgs("waitForAnimations").returns(false)
|
||||
@@ -428,7 +430,8 @@ describe "$Cypress.Cy Text Commands", ->
|
||||
@cy.get(":text:first").invoke("val", "foo").type(" bar").then ($text) ->
|
||||
expect($text).to.have.value("foo bar")
|
||||
|
||||
it "inserts text after existing text on input[type=number]", ->
|
||||
## FIXME: legitimate bug
|
||||
it.skip "inserts text after existing text on input[type=number]", ->
|
||||
@cy.get("#input-types [type=number]").invoke("val", "12").type("34").then ($text) ->
|
||||
expect($text).to.have.value("1234")
|
||||
|
||||
@@ -441,7 +444,8 @@ describe "$Cypress.Cy Text Commands", ->
|
||||
@cy.get(":text:first").type("50").then ($input) ->
|
||||
expect($input).to.have.value("50")
|
||||
|
||||
it "overwrites text on input[type=number] when input has existing text", ->
|
||||
## FIXME: legitimate bug
|
||||
it.skip "overwrites text on input[type=number] when input has existing text", ->
|
||||
## when the text is clicked we want to
|
||||
## select everything in it
|
||||
@cy.$$("#input-types [type=number]").val("0").click ->
|
||||
@@ -454,7 +458,8 @@ describe "$Cypress.Cy Text Commands", ->
|
||||
@cy.get("#input-types [type=email]").type("brian@foo.com").then ($text) ->
|
||||
expect($text).to.have.value("brian@foo.com")
|
||||
|
||||
it "inserts text after existing text on input[type=email]", ->
|
||||
## FIXME: legitimate bug
|
||||
it.skip "inserts text after existing text on input[type=email]", ->
|
||||
@cy.get("#input-types [type=email]").invoke("val", "brian@foo.c").type("om").then ($text) ->
|
||||
expect($text).to.have.value("brian@foo.com")
|
||||
|
||||
@@ -1776,7 +1781,7 @@ describe "$Cypress.Cy Text Commands", ->
|
||||
@cy.get(":text:first").type("foo")
|
||||
|
||||
it "snapshots before typing", (done) ->
|
||||
@cy.$$(":text:first").keydown =>
|
||||
@cy.$$(":text:first").one "keydown", =>
|
||||
expect(@log.get("snapshots").length).to.eq(1)
|
||||
expect(@log.get("snapshots")[0].name).to.eq("before")
|
||||
expect(@log.get("snapshots")[0].body).to.be.an("object")
|
||||
|
||||
@@ -40,9 +40,9 @@ describe "$Cypress.Cy Fixtures Commands", ->
|
||||
@cy.fixture("foo", "ascii", {timeout: 1000}).then (obj) ->
|
||||
expect(obj).to.deep.eq {foo: "bar"}
|
||||
|
||||
## FIXME
|
||||
describe.skip "cancellation", ->
|
||||
it "cancels promise", (done) ->
|
||||
describe "cancellation", ->
|
||||
## FIXME: fails when running all tests in this file
|
||||
it.skip "cancels promise", (done) ->
|
||||
## respond after 50 ms
|
||||
@respondWith({}, 50)
|
||||
|
||||
|
||||
@@ -204,8 +204,7 @@ describe "$Cypress.Cy Navigation Commands", ->
|
||||
.visit("/fixtures/sinon.html")
|
||||
.go("back", {timeout: 1})
|
||||
|
||||
## FIXME: flaky!
|
||||
it.skip "only logs once on error", (done) ->
|
||||
it "only logs once on error", (done) ->
|
||||
logs = []
|
||||
|
||||
@Cypress.on "log", (attrs, log) =>
|
||||
@@ -297,9 +296,9 @@ describe "$Cypress.Cy Navigation Commands", ->
|
||||
|
||||
it "can visit pages on the same originPolicy", ->
|
||||
@cy
|
||||
.visit("http://localhost:3500")
|
||||
.visit("http://localhost:3500")
|
||||
.visit("http://localhost:3500")
|
||||
.visit("http://localhost:3500/blank.html")
|
||||
.visit("http://localhost:3500/blank.html")
|
||||
.visit("http://localhost:3500/blank.html")
|
||||
|
||||
it "can visit pages on different subdomain but same originPolicy", ->
|
||||
$remoteIframe = @cy.privateState("$remoteIframe")
|
||||
@@ -312,8 +311,8 @@ describe "$Cypress.Cy Navigation Commands", ->
|
||||
@sandbox.stub(@cy, "_src", load)
|
||||
|
||||
## make it seem like we're already on www.foobar.com:3500
|
||||
one = @Cypress.Location.create("http://www.foobar.com:3500")
|
||||
two = @Cypress.Location.create("http://help.foobar.com:3500")
|
||||
one = @Cypress.Location.create("http://www.foobar.com:3500/blank.html")
|
||||
two = @Cypress.Location.create("http://help.foobar.com:3500/blank.html")
|
||||
|
||||
@sandbox.stub(@cy, "_existing")
|
||||
.onCall(0).returns(one)
|
||||
@@ -322,8 +321,8 @@ describe "$Cypress.Cy Navigation Commands", ->
|
||||
trigger = @sandbox.spy(@Cypress, "trigger")
|
||||
|
||||
@cy
|
||||
.visit("http://www.foobar.com:3500")
|
||||
.visit("http://help.foobar.com:3500")
|
||||
.visit("http://www.foobar.com:3500/blank.html")
|
||||
.visit("http://help.foobar.com:3500/blank.html")
|
||||
.then ->
|
||||
## we should never have to go across domains even though
|
||||
## we're visiting a subdomain
|
||||
@@ -357,22 +356,22 @@ describe "$Cypress.Cy Navigation Commands", ->
|
||||
.visit("/hash.html?foo#bar") ## yes (2)
|
||||
.visit("/hash.html?foo#foo") ## no (2)
|
||||
.visit("/hash.html?bar#bar") ## yes (3)
|
||||
.visit("/index.html?bar#bar") ## yes (4)
|
||||
.visit("/index.html?baz#bar") ## yes (5)
|
||||
.visit("/index.html#bar") ## yes (6)
|
||||
.visit("/index.html") ## yes (7)
|
||||
.visit("/index.html#baz") ## no (7)
|
||||
.visit("/index.html#") ## no (7)
|
||||
.visit("/blank.html?bar#bar") ## yes (4)
|
||||
.visit("/blank.html?baz#bar") ## yes (5)
|
||||
.visit("/blank.html#bar") ## yes (6)
|
||||
.visit("/blank.html") ## yes (7)
|
||||
.visit("/blank.html#baz") ## no (7)
|
||||
.visit("/blank.html#") ## no (7)
|
||||
.then ->
|
||||
expect(count).to.eq(7)
|
||||
expect(urls).to.deep.eq([
|
||||
"about:blank"
|
||||
"http://localhost:3500/hash.html?foo#bar"
|
||||
"http://localhost:3500/hash.html?bar#bar"
|
||||
"http://localhost:3500/index.html?bar#bar"
|
||||
"http://localhost:3500/index.html?baz#bar"
|
||||
"http://localhost:3500/index.html#bar"
|
||||
"http://localhost:3500/index.html"
|
||||
"http://localhost:3500/blank.html?bar#bar"
|
||||
"http://localhost:3500/blank.html?baz#bar"
|
||||
"http://localhost:3500/blank.html#bar"
|
||||
"http://localhost:3500/blank.html"
|
||||
])
|
||||
|
||||
describe "when origins don't match", ->
|
||||
@@ -500,6 +499,7 @@ describe "$Cypress.Cy Navigation Commands", ->
|
||||
|
||||
describe ".log", ->
|
||||
beforeEach ->
|
||||
@sandbox.stub(@Cypress, "getEmissions").returns([])
|
||||
@Cypress.on "log", (attrs, @log) =>
|
||||
|
||||
it "preserves url on subsequent visits", ->
|
||||
@@ -510,27 +510,27 @@ describe "$Cypress.Cy Navigation Commands", ->
|
||||
@Cypress.on "log", (attrs, log) ->
|
||||
expect(log.pick("name", "message")).to.deep.eq {
|
||||
name: "visit"
|
||||
message: "localhost:4200/app/foo#/hash"
|
||||
message: "localhost:3500/app/foo#/hash"
|
||||
}
|
||||
|
||||
done()
|
||||
|
||||
@cy.visit("localhost:4200/app/foo#/hash")
|
||||
@cy.visit("localhost:3500/app/foo#/hash")
|
||||
|
||||
it "logs obj once complete", ->
|
||||
@cy.visit("http://localhost:3500/index.html").then ->
|
||||
@cy.visit("http://localhost:3500/blank.html").then ->
|
||||
obj = {
|
||||
state: "passed"
|
||||
name: "visit"
|
||||
message: "http://localhost:3500/index.html"
|
||||
url: "http://localhost:3500/index.html"
|
||||
message: "http://localhost:3500/blank.html"
|
||||
url: "http://localhost:3500/blank.html"
|
||||
}
|
||||
|
||||
_.each obj, (value, key) =>
|
||||
expect(@log.get(key)).deep.eq(value, "expected key: #{key} to eq value: #{value}")
|
||||
|
||||
it "snapshots once", ->
|
||||
@cy.visit("/index.html").then ->
|
||||
@cy.visit("/blank.html").then ->
|
||||
expect(@log.get("snapshots").length).to.eq(1)
|
||||
expect(@log.get("snapshots")[0]).to.be.an("object")
|
||||
|
||||
@@ -632,7 +632,7 @@ describe "$Cypress.Cy Navigation Commands", ->
|
||||
expect(@log.get("error")).to.eq err
|
||||
done()
|
||||
|
||||
@cy.visit("/index.html")
|
||||
@cy.visit("/blank.html")
|
||||
|
||||
it "logs once on error", (done) ->
|
||||
@sandbox.stub(@cy, "_resolveUrl").rejects(new Error)
|
||||
@@ -646,7 +646,7 @@ describe "$Cypress.Cy Navigation Commands", ->
|
||||
expect(logs).to.have.length(1)
|
||||
done()
|
||||
|
||||
@cy.visit("/index.html")
|
||||
@cy.visit("/blank.html")
|
||||
|
||||
it "logs once on timeout error", (done) ->
|
||||
logs = []
|
||||
@@ -708,8 +708,8 @@ describe "$Cypress.Cy Navigation Commands", ->
|
||||
done()
|
||||
|
||||
@cy
|
||||
.visit("")
|
||||
.visit("http://localhost:3501")
|
||||
.visit("http://localhost:3500/blank.html")
|
||||
.visit("http://localhost:3501/blank.html")
|
||||
|
||||
it "throws when attempting to visit a 2nd domain on different protocol", (done) ->
|
||||
logs = []
|
||||
@@ -724,8 +724,8 @@ describe "$Cypress.Cy Navigation Commands", ->
|
||||
done()
|
||||
|
||||
@cy
|
||||
.visit("")
|
||||
.visit("https://localhost:3500")
|
||||
.visit("http://localhost:3500/blank.html")
|
||||
.visit("https://localhost:3500/blank.html")
|
||||
|
||||
it "throws when attempting to visit a 2nd domain on different host", (done) ->
|
||||
logs = []
|
||||
@@ -740,8 +740,8 @@ describe "$Cypress.Cy Navigation Commands", ->
|
||||
done()
|
||||
|
||||
@cy
|
||||
.visit("")
|
||||
.visit("http://google.com:3500")
|
||||
.visit("http://localhost:3500/blank.html")
|
||||
.visit("http://google.com:3500/blank.html")
|
||||
|
||||
it "throws attemping to visit 2 unique ip addresses", (done) ->
|
||||
$remoteIframe = @cy.privateState("$remoteIframe")
|
||||
@@ -756,7 +756,7 @@ describe "$Cypress.Cy Navigation Commands", ->
|
||||
logs = []
|
||||
|
||||
## make it seem like we're already on http://127.0.0.1:3500
|
||||
one = @Cypress.Location.create("http://127.0.0.1:3500")
|
||||
one = @Cypress.Location.create("http://127.0.0.1:3500/blank.html")
|
||||
@sandbox.stub(@cy, "_existing")
|
||||
.returns(one)
|
||||
|
||||
@@ -770,20 +770,20 @@ describe "$Cypress.Cy Navigation Commands", ->
|
||||
done()
|
||||
|
||||
@cy
|
||||
.visit("http://127.0.0.1:3500")
|
||||
.visit("http://126.0.0.1:3500")
|
||||
.visit("http://127.0.0.1:3500/blank.html")
|
||||
.visit("http://126.0.0.1:3500/blank.html")
|
||||
|
||||
it "does not call resolve:url when throws attemping to visit a 2nd domain", (done) ->
|
||||
trigger = @sandbox.spy(@Cypress, "trigger")
|
||||
|
||||
@cy.on "fail", (err) =>
|
||||
expect(trigger).to.be.calledWithMatch("resolve:url", "http://localhost:3500")
|
||||
expect(trigger).not.to.be.calledWithMatch("resolve:url", "http://google.com:3500")
|
||||
expect(trigger).to.be.calledWithMatch("resolve:url", "http://localhost:3500/blank.html")
|
||||
expect(trigger).not.to.be.calledWithMatch("resolve:url", "http://google.com:3500/blank.html")
|
||||
done()
|
||||
|
||||
@cy
|
||||
.visit("http://localhost:3500")
|
||||
.visit("http://google.com:3500")
|
||||
.visit("http://localhost:3500/blank.html")
|
||||
.visit("http://google.com:3500/blank.html")
|
||||
|
||||
it "displays loading_network_failed when _resolveUrl throws", (done) ->
|
||||
err1 = new Error("connect ECONNREFUSED 127.0.0.1:64646")
|
||||
|
||||
@@ -60,14 +60,12 @@ describe "$Cypress.Cy Listeners Extensions", ->
|
||||
@cy.get("a#change-page").click().then ->
|
||||
expect(@isReady).not.to.be.calledWith false
|
||||
|
||||
## FIXME: the following 2 fail when running all test files
|
||||
|
||||
it.skip "sets initial cookies", ->
|
||||
it "sets initial cookies", ->
|
||||
setInitial = @sandbox.stub @Cypress.Cookies, "setInitial"
|
||||
@cy.get("a#change-page").click().then ->
|
||||
expect(setInitial).to.be.called
|
||||
|
||||
it.skip "calls cy#loading", ->
|
||||
it "calls cy#loading", ->
|
||||
loading = @sandbox.stub @cy, "loading"
|
||||
@cy.get("a#change-page").click().then ->
|
||||
expect(loading).to.be.called
|
||||
|
||||
@@ -849,6 +849,7 @@ describe "$Cypress.Log API", ->
|
||||
|
||||
@cy.get("button").contains("asdfasdfasdfasdf")
|
||||
|
||||
## FIXME: timed out once on full run
|
||||
it "#consoleProps for nested children commands", (done) ->
|
||||
@Cypress.on "log", (attrs, @log) =>
|
||||
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
"start": "./bin/cypress-electron",
|
||||
"test": "mocha --compilers coffee:../coffee/register",
|
||||
"postinstall": "./bin/cypress-electron --install",
|
||||
"clean-deps": "rm -rf node_modules",
|
||||
"clean-all": "npm run clean-deps"
|
||||
"clean-deps": "rm -rf node_modules"
|
||||
},
|
||||
"bin": {
|
||||
"cypress-electron": "./bin/cypress-electron"
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"clean-deps": "rm -rf node_modules",
|
||||
"test-lib": "NODE_ENV=test mocha",
|
||||
"test": "cypress run",
|
||||
"test": "NODE_ENV=test mocha",
|
||||
"test-e2e": "cypress run",
|
||||
"build": "./bin/build.sh && gulp build",
|
||||
"predeploy": "npm run build",
|
||||
"deploy": "gulp deploy",
|
||||
|
||||
@@ -4,15 +4,13 @@
|
||||
"description": "Cypress Chrome Extension",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"watch-dev": "gulp watch",
|
||||
"build-dev": "gulp build",
|
||||
"watch": "gulp watch",
|
||||
"build": "gulp build",
|
||||
"build-prod": "gulp build",
|
||||
"test": "npm run test-unit-once",
|
||||
"test-once": "npm run test-unit-once",
|
||||
"test-unit-once": "NODE_ENV=test mocha --require test-setup.js",
|
||||
"test": "NODE_ENV=test mocha --require test-setup.js",
|
||||
"test-watch": "npm run test -- --watch",
|
||||
"clean": "gulp clean",
|
||||
"clean-deps": "rm -rf node_modules",
|
||||
"clean-all": "npm run clean && npm run clean-deps"
|
||||
"clean-deps": "rm -rf node_modules"
|
||||
},
|
||||
"files": [
|
||||
"app",
|
||||
|
||||
Vendored
-46
@@ -1,46 +0,0 @@
|
||||
// all common type definition for this module
|
||||
|
||||
type NotInstalledError = Error & {notInstalled: boolean}
|
||||
|
||||
type BrowserNotFoundError = Error & {specificBrowserNotFound: boolean}
|
||||
|
||||
interface ExtraLauncherMethods {
|
||||
update: Function,
|
||||
detect: Function
|
||||
}
|
||||
|
||||
type LauncherLaunch = (browsers?: any[]) => Promise<any>
|
||||
|
||||
type LauncherApi = LauncherLaunch & ExtraLauncherMethods
|
||||
|
||||
type Browser = {
|
||||
name: string,
|
||||
re: RegExp,
|
||||
profile: boolean,
|
||||
binary: string,
|
||||
executable: string,
|
||||
version?: string,
|
||||
majorVersion?: string,
|
||||
page?: string
|
||||
}
|
||||
|
||||
// missing type definitions for 3rd party libraries
|
||||
// https://glebbahmutov.com/blog/trying-typescript/#manual-types-for-3rd-party-libraries
|
||||
declare module 'execa' {
|
||||
type ExecaResult = {
|
||||
stdout: string
|
||||
}
|
||||
interface Execa {
|
||||
shell: (cmd:string) => Promise<ExecaResult>
|
||||
}
|
||||
const execa: Execa
|
||||
export = execa
|
||||
}
|
||||
|
||||
declare module 'plist' {
|
||||
interface Plist {
|
||||
parse: (s:string) => any
|
||||
}
|
||||
const plist: Plist
|
||||
export = plist
|
||||
}
|
||||
@@ -1,2 +1,14 @@
|
||||
// @ts-check
|
||||
module.exports = require("./lib/launcher")
|
||||
|
||||
// compile TypeScript files on the fly using
|
||||
// Node require hook project
|
||||
require('../ts/register')
|
||||
const launcher = require("./lib/launcher")
|
||||
module.exports = launcher
|
||||
|
||||
if (!module.parent) {
|
||||
// quick way to check if TS is working
|
||||
console.log('Launcher project exports')
|
||||
console.log(launcher)
|
||||
console.log('please use it as a module, not from CLI')
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {log} from './log'
|
||||
import {find, map} from 'lodash'
|
||||
import cp = require('child_process')
|
||||
import {BrowserNotFoundError} from './types'
|
||||
|
||||
type FoundBrowser = {
|
||||
name: string,
|
||||
@@ -31,7 +32,7 @@ export function launch (browsers:FoundBrowser[],
|
||||
}
|
||||
|
||||
if (url) {
|
||||
args.unshift(url)
|
||||
args = [url].concat(args)
|
||||
}
|
||||
|
||||
return cp.spawn(browser.path, args, {stdio: 'ignore'})
|
||||
@@ -1,4 +1,5 @@
|
||||
import {log} from '../log'
|
||||
import {NotInstalledError} from '../types'
|
||||
import execa = require('execa')
|
||||
|
||||
import fs = require('fs-extra')
|
||||
@@ -1,10 +1,12 @@
|
||||
import {linuxBrowser} from './linux'
|
||||
import darwin from './darwin'
|
||||
import {log} from './log'
|
||||
import {Browser, NotInstalledError} from './types'
|
||||
import * as Bluebird from 'bluebird'
|
||||
|
||||
import _ = require('lodash')
|
||||
import os = require('os')
|
||||
import Promise = require('bluebird')
|
||||
// import Promise = require('bluebird')
|
||||
|
||||
const browsers:Browser[] = [
|
||||
{
|
||||
@@ -39,21 +41,21 @@ const setMajorVersion = (obj:Browser) => {
|
||||
|
||||
type MacBrowserName = 'chrome' | 'chromium' | 'canary'
|
||||
|
||||
function lookup (platform:string, obj:Browser) {
|
||||
function lookup (platform:string, obj:Browser):Promise<Object> {
|
||||
log('looking up %s on %s platform', obj.name, platform)
|
||||
switch (platform) {
|
||||
case 'darwin':
|
||||
const browserName:MacBrowserName = obj.name as MacBrowserName
|
||||
const fn = darwin[browserName]
|
||||
if (fn) {
|
||||
return fn.get(obj.executable)
|
||||
return fn.get(obj.executable) as any as Promise<Object>
|
||||
}
|
||||
const err: NotInstalledError =
|
||||
new Error(`Browser not installed: ${obj.name}`) as NotInstalledError
|
||||
err.notInstalled = true
|
||||
return Promise.reject(err)
|
||||
throw err
|
||||
case 'linux':
|
||||
return linuxBrowser.get(obj.binary, obj.re)
|
||||
return linuxBrowser.get(obj.binary, obj.re) as any as Promise<Object>
|
||||
default:
|
||||
throw new Error(`Cannot lookup browser ${obj.name} on ${platform}`)
|
||||
}
|
||||
@@ -62,7 +64,7 @@ function lookup (platform:string, obj:Browser) {
|
||||
function checkOneBrowser(browser:Browser) {
|
||||
const platform = os.platform()
|
||||
return lookup(platform, browser)
|
||||
.then(props => {
|
||||
.then((props:object) => {
|
||||
return _.chain({})
|
||||
.extend(browser, props)
|
||||
.pick('name', 'type', 'version', 'path')
|
||||
@@ -79,9 +81,9 @@ function checkOneBrowser(browser:Browser) {
|
||||
}
|
||||
|
||||
/** returns list of detected browsers */
|
||||
function detectBrowsers (): Promise<Browser[]> {
|
||||
return Promise.map(browsers, checkOneBrowser)
|
||||
.then(_.compact) as Promise<Browser[]>
|
||||
function detectBrowsers (): Bluebird<Browser[]> {
|
||||
return Bluebird.map(browsers, checkOneBrowser)
|
||||
.then(_.compact) as Bluebird<Browser[]>
|
||||
}
|
||||
|
||||
export default detectBrowsers
|
||||
@@ -1,6 +1,7 @@
|
||||
import {writeJson} from 'fs-extra'
|
||||
import {launch} from './browsers'
|
||||
import detect from './detect'
|
||||
import {Browser, LauncherApi} from './types'
|
||||
|
||||
const Promise = require('bluebird')
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import cp = require('child_process')
|
||||
import Promise = require('bluebird')
|
||||
import {NotInstalledError} from '../types'
|
||||
|
||||
const execAsync = Promise.promisify(cp.exec)
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
export type Browser = {
|
||||
name: string,
|
||||
re: RegExp,
|
||||
profile: boolean,
|
||||
binary: string,
|
||||
executable: string,
|
||||
version?: string,
|
||||
majorVersion?: string,
|
||||
page?: string
|
||||
}
|
||||
|
||||
interface ExtraLauncherMethods {
|
||||
update: Function,
|
||||
detect: Function
|
||||
}
|
||||
|
||||
type LauncherLaunch = (browsers?: any[]) => Promise<any>
|
||||
|
||||
export type LauncherApi = LauncherLaunch & ExtraLauncherMethods
|
||||
|
||||
// all common type definition for this module
|
||||
|
||||
export type NotInstalledError = Error & {notInstalled: boolean}
|
||||
|
||||
export type BrowserNotFoundError = Error & {specificBrowserNotFound: boolean}
|
||||
@@ -3,16 +3,13 @@
|
||||
"version": "0.1.1",
|
||||
"description": "Internal lib for spawning browser processes",
|
||||
"main": "index.js",
|
||||
"types": "./index.d.ts",
|
||||
"types": "../ts/index.d.ts",
|
||||
"scripts": {
|
||||
"clean-deps": "rm -rf node_modules",
|
||||
"clean-all": "npm run clean-deps",
|
||||
"lint": "tslint --type-check --project . --fix --format stylish src/**/*.ts",
|
||||
"build": "tsc",
|
||||
"build-dev": "npm run build",
|
||||
"prebuild": "npm run lint",
|
||||
"build": "npm run lint",
|
||||
"pretest": "npm run lint",
|
||||
"test": "mocha",
|
||||
"build-and-test": "npm run build && npm test"
|
||||
"clean-deps": "rm -rf node_modules",
|
||||
"lint": "tslint --type-check --project .. --fix --format stylish launcher/lib/*.ts launcher/lib/**/*.ts"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
test/unit
|
||||
--compilers coffee:../coffee/register
|
||||
--compilers coffee:../coffee/register,ts:../ts/register
|
||||
--recursive
|
||||
|
||||
@@ -4,15 +4,12 @@
|
||||
"main": "lib/reporter",
|
||||
"browser": "src/main",
|
||||
"scripts": {
|
||||
"build-dev": "node ./scripts/build-dev.js",
|
||||
"build": "node ./scripts/build-dev.js",
|
||||
"build-prod": "node ./scripts/build-prod.js",
|
||||
"watch": "node ./scripts/watch.js",
|
||||
"clean": "zunder clean",
|
||||
"clean-deps": "rm -rf node_modules",
|
||||
"clean-all": "npm run clean && npm run clean-deps",
|
||||
"test": "npm run test-unit-once",
|
||||
"test-once": "npm run test-unit-once",
|
||||
"test-unit-once": "node ./scripts/test.js",
|
||||
"watch-dev": "node ./scripts/watch.js"
|
||||
"test": "node ./scripts/test.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -12,15 +12,12 @@
|
||||
},
|
||||
"homepage": "https://github.com/cypress-io/cypress-core-runner#readme",
|
||||
"scripts": {
|
||||
"build-dev": "node ./scripts/build-dev.js",
|
||||
"build": "node ./scripts/build-dev.js",
|
||||
"build-prod": "node ./scripts/build-prod.js",
|
||||
"watch": "node ./scripts/watch.js",
|
||||
"clean": "zunder clean",
|
||||
"clean-deps": "rm -rf node_modules",
|
||||
"clean-all": "npm run clean && npm run clean-deps",
|
||||
"test": "npm run test-unit-once",
|
||||
"test-once": "npm run test-unit-once",
|
||||
"test-unit-once": "node ./scripts/test.js",
|
||||
"watch-dev": "node ./scripts/watch.js",
|
||||
"test": "node ./scripts/test.js",
|
||||
"lint": "eslint src/**/*.jsx src/**/*.js"
|
||||
},
|
||||
"files": [
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
process.env.UV_THREADPOOL_SIZE = 128
|
||||
require('graceful-fs').gracefulify(require('fs'))
|
||||
require("../ts/register")
|
||||
require("../coffee/register")
|
||||
require && require.extensions && delete require.extensions[".litcoffee"]
|
||||
require && require.extensions && delete require.extensions[".coffee.md"]
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
require("../ts/register")
|
||||
require("../coffee/register")
|
||||
require("./lib/repl")
|
||||
|
||||
@@ -10,4 +10,4 @@ DEBUG=nock.*,-nock.common,-nock.scope,socket.io:*,xvfb-maybe \
|
||||
BROWSER=$BROWSER \
|
||||
xvfb-maybe --xvfb-run-args "-s \"-screen 0 1280x1024x8\"" mocha $SPEC \
|
||||
--recursive \
|
||||
--compilers coffee:../coffee/register
|
||||
--compilers coffee:../coffee/register,ts:../ts/register
|
||||
|
||||
@@ -6,10 +6,7 @@
|
||||
"scripts": {
|
||||
"test": "NODE_ENV=test mocha",
|
||||
"test-watch": "NODE_ENV=test mocha --watch",
|
||||
"test-once": "npm run test-unit-once",
|
||||
"test-unit-once": "NODE_ENV=test mocha",
|
||||
"clean-deps": "rm -rf node_modules",
|
||||
"clean-all": "npm run clean-deps"
|
||||
"clean-deps": "rm -rf node_modules"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "static",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build-dev": "gulp build",
|
||||
"build": "gulp build",
|
||||
"test": "echo 'Nothing to test yet'"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
Vendored
+20
@@ -0,0 +1,20 @@
|
||||
// missing type definitions for 3rd party libraries
|
||||
// https://glebbahmutov.com/blog/trying-typescript/#manual-types-for-3rd-party-libraries
|
||||
declare module 'execa' {
|
||||
type ExecaResult = {
|
||||
stdout: string
|
||||
}
|
||||
interface Execa {
|
||||
shell: (cmd:string) => Promise<ExecaResult>
|
||||
}
|
||||
const execa: Execa
|
||||
export = execa
|
||||
}
|
||||
|
||||
declare module 'plist' {
|
||||
interface Plist {
|
||||
parse: (s:string) => any
|
||||
}
|
||||
const plist: Plist
|
||||
export = plist
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
// gives anyone access to ts-node
|
||||
// https://github.com/TypeStrong/ts-node#programmatic-usage
|
||||
module.exports = require('ts-node')
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "ts",
|
||||
"version": "1.0.0",
|
||||
"description": "TypeScript runtime Node hook",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "node test"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"ts-node": "^3.0.4",
|
||||
"typescript": "^2.3.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// register TypeScript Node require hook
|
||||
// https://github.com/TypeStrong/ts-node#programmatic-usage
|
||||
const project = require('path').join(__dirname, '../tsconfig.json')
|
||||
require('ts-node').register({
|
||||
project
|
||||
})
|
||||
|
||||
// do we need to prevent any other TypeScript hooks?
|
||||
// like ../coffee/register.js does?
|
||||
@@ -0,0 +1,2 @@
|
||||
require('../register')
|
||||
require('./spec')
|
||||
@@ -0,0 +1,2 @@
|
||||
const add = (a: number, b: number) => a + b
|
||||
console.assert(add(10, 2) === 12, '10 + 2 should be 12')
|
||||
@@ -10,8 +10,8 @@
|
||||
// "declaration": true, /* Generates corresponding '.d.ts' file. */
|
||||
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||
"outDir": "./lib", /* Redirect output structure to the directory. */
|
||||
// "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||
// "outDir": "./", /* Redirect output structure to the directory. */
|
||||
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||
// "removeComments": true, /* Do not emit comments to output. */
|
||||
// "noEmit": true, /* Do not emit outputs. */
|
||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||
@@ -19,11 +19,11 @@
|
||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||
|
||||
/* Strict Type-Checking Options */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
"strictNullChecks": true, /* Enable strict null checks. */
|
||||
"noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
||||
"alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* Enable strict null checks. */
|
||||
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
||||
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||
|
||||
/* Additional Checks */
|
||||
"noUnusedLocals": true, /* Report errors on unused locals. */
|
||||
@@ -32,12 +32,12 @@
|
||||
"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": "./src" /* Base directory to resolve non-absolute module names. */
|
||||
"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": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
// "typeRoots": [] /* List of folders to include type definitions from. */
|
||||
// "types": [] /* Type declaration files to be included in compilation. */
|
||||
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||
// "types": [] /* Type declaration files to be included in compilation. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||
|
||||
/* Source Map Options */
|
||||
@@ -49,9 +49,5 @@
|
||||
/* Experimental Options */
|
||||
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||
},
|
||||
"include": [
|
||||
"./src/*.ts",
|
||||
"./index.d.ts"
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user