From 31d518f3e1db706080904eb846bd6a48a3789da4 Mon Sep 17 00:00:00 2001 From: alecmerdler Date: Tue, 6 Jun 2017 16:03:13 -0700 Subject: [PATCH] added Protractor for end-to-end testing --- package.json | 3 + .../manage-trigger.view-object.ts | 62 +++ static/test/e2e/sanity.scenario.ts | 19 + static/test/e2e/trigger-creation.scenario.ts | 155 ++++++++ static/test/protractor.conf.ts | 66 ++++ yarn.lock | 364 +++++++++++------- 6 files changed, 524 insertions(+), 145 deletions(-) create mode 100644 static/js/directives/ui/manage-trigger/manage-trigger.view-object.ts create mode 100644 static/test/e2e/sanity.scenario.ts create mode 100644 static/test/e2e/trigger-creation.scenario.ts create mode 100644 static/test/protractor.conf.ts diff --git a/package.json b/package.json index a226306ca..11ffa8c8e 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "dev": "./node_modules/.bin/karma start --browsers ChromeHeadless", "test": "./node_modules/.bin/karma start --single-run --browsers ChromeHeadless", "test:node": "JASMINE_CONFIG_PATH=static/test/jasmine.json ./node_modules/.bin/jasmine-ts './static/js/**/*.spec.ts'", + "e2e": "./node_modules/.bin/ts-node ./node_modules/.bin/protractor static/test/protractor.conf.ts", "build": "NODE_ENV=production ./node_modules/.bin/webpack --progress", "watch": "./node_modules/.bin/webpack --watch" }, @@ -65,11 +66,13 @@ "karma-jasmine": "^0.3.8", "karma-webpack": "^1.8.1", "ngtemplate-loader": "^1.3.1", + "protractor": "^5.1.2", "script-loader": "^0.7.0", "source-map-loader": "0.1.5", "style-loader": "0.13.1", "ts-loader": "^0.9.5", "ts-mocks": "^0.2.2", + "ts-node": "^3.0.6", "typescript": "^2.2.1", "typings": "1.4.0", "webpack": "^2.2" diff --git a/static/js/directives/ui/manage-trigger/manage-trigger.view-object.ts b/static/js/directives/ui/manage-trigger/manage-trigger.view-object.ts new file mode 100644 index 000000000..3998cfb27 --- /dev/null +++ b/static/js/directives/ui/manage-trigger/manage-trigger.view-object.ts @@ -0,0 +1,62 @@ +import { element, by, browser, $, ElementFinder, ExpectedConditions as until } from 'protractor'; + + +export class ManageTriggerViewObject { + + public sections: {[name: string]: ElementFinder} = { + namespace: $('linear-workflow-section[section-id=namespace]'), + githostrepo: $('linear-workflow-section[section-id=repo][section-title="Select Repository"]'), + customrepo: $('linear-workflow-section[section-id=repo][section-title="Git Repository"]'), + triggeroptions: $('linear-workflow-section[section-id=triggeroptions]'), + dockerfilelocation: $('linear-workflow-section[section-id=dockerfilelocation]'), + contextlocation: $('linear-workflow-section[section-id=contextlocation]'), + robot: $('linear-workflow-section[section-id=robot]'), + verification: $('linear-workflow-section[section-id=verification]'), + }; + + private customGitRepoInput: ElementFinder = element(by.model('$ctrl.buildSource')); + private dockerfileLocationInput: ElementFinder = this.sections['dockerfilelocation'].$('input'); + private dockerfileLocationDropdownButton: ElementFinder = this.sections['dockerfilelocation'].$('button[data-toggle=dropdown'); + private dockerContextInput: ElementFinder = this.sections['contextlocation'].$('input'); + private dockerContextDropdownButton: ElementFinder = this.sections['contextlocation'].$('button[data-toggle=dropdown'); + private robotAccountOptions: ElementFinder = this.sections['robot'].element(by.repeater('$ctrl.orderedData.visibleEntries')); + + public continue(): Promise { + return Promise.resolve(element(by.buttonText('Continue')).click()); + } + + public enterRepositoryURL(url: string): Promise { + browser.wait(until.presenceOf(this.customGitRepoInput)); + this.customGitRepoInput.clear(); + + return Promise.resolve(this.customGitRepoInput.sendKeys(url)); + } + + public enterDockerfileLocation(path: string): Promise { + browser.wait(until.presenceOf(this.dockerfileLocationInput)); + this.dockerfileLocationInput.clear(); + + return Promise.resolve(this.dockerfileLocationInput.sendKeys(path)); + } + + public getDockerfileSuggestions(): Promise { + return Promise.resolve(this.dockerfileLocationDropdownButton.click()) + .then(() => element.all(by.repeater('$ctrl.paths')).map(result => result.getText())); + } + + public enterDockerContext(path: string): Promise { + browser.wait(until.presenceOf(this.dockerContextInput)); + this.dockerContextInput.clear(); + + return Promise.resolve(this.dockerContextInput.sendKeys(path)); + } + + public getDockerContextSuggestions(): Promise { + return Promise.resolve(this.dockerContextDropdownButton.click()) + .then(() => element.all(by.repeater('$ctrl.contexts')).map(result => result.getText())); + } + + public selectRobotAccount(index: number): Promise { + return Promise.resolve(element.all(by.css('input[type=radio]')).get(index).click()); + } +} diff --git a/static/test/e2e/sanity.scenario.ts b/static/test/e2e/sanity.scenario.ts new file mode 100644 index 000000000..c2400d242 --- /dev/null +++ b/static/test/e2e/sanity.scenario.ts @@ -0,0 +1,19 @@ +import { browser } from 'protractor'; +import { appHost } from '../protractor.conf'; + + +describe("sanity test", () => { + + beforeEach(() => { + browser.get(appHost); + }); + + it("loads home view with no AngularJS errors", () => { + browser.manage().logs().get('browser') + .then((browserLog: any) => { + browserLog.forEach((log: any) => { + expect(log.message).not.toContain("angular"); + }); + }); + }); +}); diff --git a/static/test/e2e/trigger-creation.scenario.ts b/static/test/e2e/trigger-creation.scenario.ts new file mode 100644 index 000000000..61f33084c --- /dev/null +++ b/static/test/e2e/trigger-creation.scenario.ts @@ -0,0 +1,155 @@ +import { browser, element, by, $, $$ } from 'protractor'; +import { ManageTriggerViewObject } from '../../js/directives/ui/manage-trigger/manage-trigger.view-object'; +import { appHost } from '../protractor.conf'; + + +describe("Trigger Creation", () => { + const username = 'devtable'; + const password = 'password'; + var manageTriggerView: ManageTriggerViewObject = new ManageTriggerViewObject(); + + beforeAll((done) => { + browser.waitForAngularEnabled(false); + + // Sign in + browser.get(appHost); + $$('a[href="/signin/"]').get(1).click(); + $('#signin-username').sendKeys(username); + $('#signin-password').sendKeys(password); + element(by.partialButtonText('Sign in')).click(); + browser.sleep(4000).then(() => done()); + }); + + afterAll(() => { + browser.waitForAngularEnabled(true); + // TODO(alecmerdler): Delete all created triggers + }); + + describe("for custom git", () => { + + beforeAll(() => { + // Navigate to trigger setup + browser.get(`${appHost}/repository/devtable/simple?tab=builds`) + }); + + it("can select custom git repository push as a trigger option", (done) => { + element(by.buttonText('Create Build Trigger')).click(); + element(by.linkText('Custom Git Repository Push')).click(); + browser.sleep(1000); + done(); + }); + + it("shows custom git repository section first", () => { + expect(manageTriggerView.sections['customrepo'].isDisplayed()).toBe(true); + }); + + it("does not accept invalid custom git repository URL's", () => { + manageTriggerView.continue() + .then(() => fail('Should not accept empty input for repository URL')) + .catch(() => manageTriggerView.enterRepositoryURL('git@some')) + .then(() => manageTriggerView.continue()) + .then(() => fail('Should not accept invalid input for repository URL')) + .catch(() => null); + }); + + it("proceeds to Dockerfile location section when given valid URL", () => { + manageTriggerView.enterRepositoryURL('git@somegit.com:someuser/somerepo.git'); + manageTriggerView.continue() + .then(() => { + expect(manageTriggerView.sections['dockerfilelocation'].isDisplayed()).toBe(true); + }) + .catch(reason => fail(reason)); + }); + + it("does not accept Dockerfile location that does not end with a filename", () => { + manageTriggerView.enterDockerfileLocation('/') + .then(() => manageTriggerView.continue()) + .then(() => fail('Should not accept Dockerfile location that does not end with a filename')) + .catch(() => null); + }); + + it("does not provide Dockerfile location suggestions", () => { + manageTriggerView.getDockerfileSuggestions() + .then((results) => { + expect(results.length).toEqual(0); + }); + }); + + it("proceeds to Docker context location section when given a valid Dockerfile location", () => { + manageTriggerView.enterDockerfileLocation('/Dockerfile') + .then(() => manageTriggerView.continue()) + .then(() => { + expect(manageTriggerView.sections['contextlocation'].isDisplayed()).toBe(true); + }) + .catch(reason => fail(reason)); + }); + + it("does not accept invalid Docker context", () => { + manageTriggerView.enterDockerContext('') + .then(() => manageTriggerView.continue()) + .then(() => fail('Should not acccept invalid Docker context location')) + .catch(() => null); + }); + + it("provides suggestions for Docker context based on Dockerfile location", () => { + manageTriggerView.getDockerContextSuggestions() + .then((results) => { + expect(results).toContain('/'); + }); + }); + + it("proceeds to robot selection section when given valid Docker context", () => { + manageTriggerView.enterDockerContext('/') + .then(() => manageTriggerView.continue()) + .then(() => { + expect(manageTriggerView.sections['robot'].isDisplayed()).toBe(true); + }) + .catch(reason => fail(reason)); + }); + + it("allows selection of optional robot account", () => { + manageTriggerView.selectRobotAccount(0) + .catch(reason => fail(reason)); + }); + + it("proceeds to verification section", () => { + manageTriggerView.continue() + .then(() => { + expect(manageTriggerView.sections['verification'].isDisplayed()).toBe(true); + }) + .catch(reason => fail(reason)); + }); + + it("displays success message after creating the trigger", () => { + manageTriggerView.continue() + .then(() => { + browser.sleep(2000); + expect($('h3').getText()).toEqual('Trigger has been successfully activated'); + }) + .catch(reason => fail(reason)); + }); + }); + + describe("for githost", () => { + + beforeAll(() => { + // Navigate to trigger setup + browser.get(`${appHost}/repository/devtable/simple?tab=builds`); + }); + + it("can select GitHub repository push as a trigger option", () => { + element(by.partialButtonText('Create Build Trigger')).click(); + element(by.linkText('GitHub Repository Push')).click(); + }); + + it("redirects to GitHub login page for granting authentication", () => { + expect(browser.getCurrentUrl()).toContain('github.com'); + + // TODO: Which credentials do we use to login to GitHub? + }); + + xit("shows namespace select section first", () => { + expect(manageTriggerView.sections['namespace'].isDisplayed()).toBe(true); + }); + }); +}); diff --git a/static/test/protractor.conf.ts b/static/test/protractor.conf.ts new file mode 100644 index 000000000..9016c1743 --- /dev/null +++ b/static/test/protractor.conf.ts @@ -0,0 +1,66 @@ +import { Config, browser } from 'protractor'; +import * as request from 'request'; + + +/* +* Use a set environment variable or default value for the app host. +*/ +export const appHost: string = process.env.APP_HOST || 'http://localhost:5000'; + + +/** + * Protractor is configured to run against a Selenium instance running locally on port 4444 and a Quay instance running + * locally on port 5000. + * Easiest method is running the Quay and Selenium containers: + * $ docker run -d --net=host -v /dev/shm:/dev/shm selenium/standalone-chrome:3.4.0 + * $ docker run -d --net=host quay.io/quay/quay + * $ yarn run e2e + */ +export const config: Config = { + framework: 'jasmine', + seleniumAddress: 'http://localhost:4444/wd/hub', + // Uncomment to run tests against local Chrome instance + // directConnect: true, + capabilities: { + browserName: 'chrome', + chromeOptions: { + args: [ + '--disable-infobars' + ], + prefs: { + 'profile.password_manager_enabled': false, + 'credentials_enable_service': false, + 'password_manager_enabled': false + } + } + }, + onPrepare: () => { + browser.driver.manage().window().maximize(); + + // Resolve promise when request returns HTTP 200 + return new Promise((resolve, reject) => { + const pollServer = (success, failure) => { + request(appHost, (error, response, body) => { + if (!error && response.statusCode == 200) { + console.log(`Successfully connected to server at ${appHost}`); + success(); + } else { + console.log(`Could not connect to server at ${appHost}`); + setTimeout(() => { + failure(success, failure); + }, 5000); + } + }); + }; + + pollServer(resolve, pollServer); + }); + }, + onComplete: () => { + browser.close(); + }, + specs: [ + './e2e/sanity.scenario.ts', + './e2e/trigger-creation.scenario.ts' + ], +}; diff --git a/yarn.lock b/yarn.lock index 47165470b..61c278bb0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -44,6 +44,10 @@ version "6.0.78" resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.78.tgz#5d4a3f579c1524e01ee21bf474e6fba09198f470" +"@types/q@^0.0.32": + version "0.0.32" + resolved "https://registry.yarnpkg.com/@types/q/-/q-0.0.32.tgz#bd284e57c84f1325da702babfc82a5328190c0c5" + "@types/react-dom@0.14.17": version "0.14.17" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-0.14.17.tgz#d8b0dec27e873c218d9075856c6ca1c5db956d5d" @@ -54,14 +58,14 @@ version "0.14.39" resolved "https://registry.yarnpkg.com/@types/react/-/react-0.14.39.tgz#11cb715768da5f7605aa2030a5dc63e77a137eb5" +"@types/selenium-webdriver@^2.53.35", "@types/selenium-webdriver@~2.53.39": + version "2.53.42" + resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-2.53.42.tgz#74cb77fb6052edaff2a8984ddafd88d419f25cac" + "@types/showdown@^1.4.32": version "1.4.32" resolved "https://registry.yarnpkg.com/@types/showdown/-/showdown-1.4.32.tgz#bb0b32dbafee23ae9575df30b227e4fc2f0cd45b" -abab@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.3.tgz#b81de5f7274ec4e756d797cd834f303642724e5d" - abbrev@1, abbrev@1.0.x: version "1.0.9" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" @@ -79,16 +83,18 @@ acorn-dynamic-import@^2.0.0: dependencies: acorn "^4.0.3" -acorn-globals@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-3.1.0.tgz#fd8270f71fbb4996b004fa880ee5d46573a731bf" - dependencies: - acorn "^4.0.4" - acorn@^4.0.3, acorn@^4.0.4: version "4.0.11" resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0" +adm-zip@0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.4.tgz#a61ed5ae6905c3aea58b3a657d25033091052736" + +adm-zip@^0.4.7: + version "0.4.7" + resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.7.tgz#8606c2cbf1c426ce8c8ec00174447fd49b6eafc1" + after@0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" @@ -213,10 +219,6 @@ arr-flatten@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b" -array-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" - array-find-index@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" @@ -225,7 +227,13 @@ array-slice@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5" -array-uniq@^1.0.2: +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1, array-uniq@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" @@ -374,6 +382,12 @@ block-stream@*: dependencies: inherits "~2.0.0" +blocking-proxy@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/blocking-proxy/-/blocking-proxy-0.0.5.tgz#462905e0dcfbea970f41aa37223dda9c07b1912b" + dependencies: + minimist "^1.2.0" + bluebird@^3.1.1, bluebird@^3.3.0: version "3.4.7" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" @@ -821,10 +835,6 @@ constants-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" -content-type-parser@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.1.tgz#c3e56988c53c65127fb46d4032a3a900246fdc94" - content-type@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" @@ -968,16 +978,6 @@ csso@~2.3.1: clap "^1.0.9" source-map "^0.5.3" -cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": - version "0.3.2" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.2.tgz#b8036170c79f07a90ff2f16e22284027a243848b" - -"cssstyle@>= 0.2.37 < 0.3.0": - version "0.2.37" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-0.2.37.tgz#541097234cb2513c83ceed3acddc27ff27987d54" - dependencies: - cssom "0.3.x" - currently-unhandled@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" @@ -1049,6 +1049,18 @@ defined@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" +del@^2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + dependencies: + globby "^5.0.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + rimraf "^2.2.8" + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -1257,7 +1269,7 @@ escape-string-regexp@^1.0.2: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" -escodegen@1.8.x, escodegen@^1.6.1: +escodegen@1.8.x: version "1.8.1" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" dependencies: @@ -1516,7 +1528,7 @@ glob@^5.0.15: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.5, glob@^7.0.6, glob@^7.1.1: +glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" dependencies: @@ -1527,6 +1539,17 @@ glob@^7.0.5, glob@^7.0.6, glob@^7.1.1: once "^1.3.0" path-is-absolute "^1.0.0" +globby@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + dependencies: + array-union "^1.0.1" + arrify "^1.0.0" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + good-listener@^1.2.0: version "1.2.2" resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50" @@ -1653,12 +1676,6 @@ html-comment-regex@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e" -html-encoding-sniffer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz#79bf7a785ea495fe66165e734153f363ff5437da" - dependencies: - whatwg-encoding "^1.0.1" - html-loader@^0.4.5: version "0.4.5" resolved "https://registry.yarnpkg.com/html-loader/-/html-loader-0.4.5.tgz#5fbcd87cd63a5c49a7fce2fe56f425e05729c68c" @@ -1726,10 +1743,6 @@ https-proxy-agent@^1.0.0: debug "2" extend "3" -iconv-lite@0.4.13: - version "0.4.13" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" - iconv-lite@0.4.15: version "0.4.15" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" @@ -1775,7 +1788,7 @@ inherits@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" -ini@~1.3.0: +ini@^1.3.4, ini@~1.3.0: version "1.3.4" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" @@ -1887,6 +1900,22 @@ is-obj@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" +is-path-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + +is-path-in-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" + dependencies: + is-path-inside "^1.0.0" + +is-path-inside@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" + dependencies: + path-is-inside "^1.0.1" + is-plain-obj@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" @@ -2002,7 +2031,7 @@ jasmine-ts@0.0.3: ts-node "^1.2.1" typescript "^2.0.0" -jasmine@^2.4.1: +jasmine@^2.4.1, jasmine@^2.5.3: version "2.5.3" resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-2.5.3.tgz#5441f254e1fc2269deb1dfd93e0e57d565ff4d22" dependencies: @@ -2010,6 +2039,10 @@ jasmine@^2.4.1: glob "^7.0.6" jasmine-core "~2.5.2" +jasminewd2@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/jasminewd2/-/jasminewd2-2.1.0.tgz#da595275d1ae631de736ac0a7c7d85c9f73ef652" + jodid25519@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" @@ -2046,32 +2079,6 @@ jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" -jsdom@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.0.0.tgz#1ee507cb2c0b16c875002476b1a8557d951353e5" - dependencies: - abab "^1.0.3" - acorn "^4.0.4" - acorn-globals "^3.1.0" - array-equal "^1.0.0" - content-type-parser "^1.0.1" - cssom ">= 0.3.2 < 0.4.0" - cssstyle ">= 0.2.37 < 0.3.0" - escodegen "^1.6.1" - html-encoding-sniffer "^1.0.1" - nwmatcher ">= 1.3.9 < 2.0.0" - parse5 "^3.0.2" - pn "^1.0.0" - request "^2.79.0" - request-promise-native "^1.0.3" - sax "^1.2.1" - symbol-tree "^3.2.1" - tough-cookie "^2.3.2" - webidl-conversions "^4.0.0" - whatwg-encoding "^1.0.1" - whatwg-url "^4.3.0" - xml-name-validator "^2.0.1" - jsesc@^0.5.0, jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" @@ -2145,10 +2152,6 @@ karma-jasmine@^0.3.8: version "0.3.8" resolved "https://registry.yarnpkg.com/karma-jasmine/-/karma-jasmine-0.3.8.tgz#5b6457791ad9b89aa173f079e3ebe1b8c805236c" -karma-jsdom-launcher@^6.1.2: - version "6.1.2" - resolved "https://registry.yarnpkg.com/karma-jsdom-launcher/-/karma-jsdom-launcher-6.1.2.tgz#f44ad3986df096463e5bfb437dc9f35db9917a05" - karma-webpack@^1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/karma-webpack/-/karma-webpack-1.8.1.tgz#39d5fd2edeea3cc3ef5b405989b37d5b0e6a3b4e" @@ -2304,7 +2307,7 @@ lodash@^3.8.0: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" -lodash@^4.13.1, lodash@^4.14.0, lodash@^4.5.0, lodash@~4.17.0: +lodash@^4.0.0, lodash@^4.14.0, lodash@^4.5.0, lodash@~4.17.0: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" @@ -2621,10 +2624,6 @@ number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" -"nwmatcher@>= 1.3.9 < 2.0.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.0.tgz#b4389362170e7ef9798c3c7716d80ebc0106fccf" - oauth-sign@~0.8.1: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" @@ -2672,7 +2671,7 @@ once@~1.3.3: dependencies: wrappy "1" -optimist@^0.6.1: +optimist@^0.6.1, optimist@~0.6.0: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" dependencies: @@ -2763,12 +2762,6 @@ parse-json@^2.1.0, parse-json@^2.2.0: dependencies: error-ex "^1.2.0" -parse5@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.2.tgz#05eff57f0ef4577fb144a79f8b9a967a6cc44510" - dependencies: - "@types/node" "^6.0.46" - parsejson@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/parsejson/-/parsejson-0.0.3.tgz#ab7e3759f209ece99437973f7d0f1f64ae0e64ab" @@ -2805,6 +2798,10 @@ path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" +path-is-inside@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + path-type@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" @@ -2833,10 +2830,6 @@ pinkie@^2.0.0, pinkie@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" -pn@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/pn/-/pn-1.0.0.tgz#1cf5a30b0d806cd18f88fc41a6b5d4ad615b3ba9" - popsicle-proxy-agent@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/popsicle-proxy-agent/-/popsicle-proxy-agent-3.0.0.tgz#b9133c55d945759ab7ee61b7711364620d3aeadc" @@ -3140,6 +3133,26 @@ promise-finally@^2.0.1: dependencies: any-promise "^1.3.0" +protractor@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/protractor/-/protractor-5.1.2.tgz#9b221741709a4c62d5cd53c6aadd54a71137e95f" + dependencies: + "@types/node" "^6.0.46" + "@types/q" "^0.0.32" + "@types/selenium-webdriver" "~2.53.39" + blocking-proxy "0.0.5" + chalk "^1.1.3" + glob "^7.0.3" + jasmine "^2.5.3" + jasminewd2 "^2.1.0" + optimist "~0.6.0" + q "1.4.1" + saucelabs "~1.3.0" + selenium-webdriver "3.0.1" + source-map-support "~0.4.0" + webdriver-js-extender "^1.0.0" + webdriver-manager "^12.0.6" + prr@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a" @@ -3162,7 +3175,7 @@ punycode@^1.2.4, punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" -q@^1.1.2: +q@1.4.1, q@^1.1.2, q@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" @@ -3407,21 +3420,7 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" -request-promise-core@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.1.tgz#3eee00b2c5aa83239cfb04c5700da36f81cd08b6" - dependencies: - lodash "^4.13.1" - -request-promise-native@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.4.tgz#86988ec8eee408e45579fce83bfd05b3adf9a155" - dependencies: - request-promise-core "1.1.1" - stealthy-require "^1.1.0" - tough-cookie ">=2.3.0" - -request@^2.79.0: +request@^2.78.0, request@^2.79.0: version "2.79.0" resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" dependencies: @@ -3474,7 +3473,7 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@2, rimraf@^2.4.4, rimraf@^2.6.0: +rimraf@2, rimraf@^2.2.8, rimraf@^2.4.4, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.0: version "2.6.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" dependencies: @@ -3500,7 +3499,17 @@ safe-buffer@^5.0.1: version "5.1.0" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.0.tgz#fe4c8460397f9eaaaa58e73be46273408a45e223" -sax@^1.2.1, sax@~1.2.1: +saucelabs@~1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/saucelabs/-/saucelabs-1.3.0.tgz#d240e8009df7fa87306ec4578a69ba3b5c424fee" + dependencies: + https-proxy-agent "^1.0.0" + +sax@0.6.x: + version "0.6.1" + resolved "https://registry.yarnpkg.com/sax/-/sax-0.6.1.tgz#563b19c7c1de892e09bfc4f2fc30e3c27f0952b9" + +sax@>=0.6.0, sax@~1.2.1: version "1.2.2" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828" @@ -3514,13 +3523,32 @@ select@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" +selenium-webdriver@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-3.0.1.tgz#a2dea5da4a97f6672e89e7ca7276cefa365147a7" + dependencies: + adm-zip "^0.4.7" + rimraf "^2.5.4" + tmp "0.0.30" + xml2js "^0.4.17" + +selenium-webdriver@^2.53.2: + version "2.53.3" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-2.53.3.tgz#d29ff5a957dff1a1b49dc457756e4e4bfbdce085" + dependencies: + adm-zip "0.4.4" + rimraf "^2.2.8" + tmp "0.0.24" + ws "^1.0.1" + xml2js "0.4.4" + semver-diff@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" dependencies: semver "^5.0.3" -"semver@2 || 3 || 4 || 5", semver@^5.0.1, semver@^5.0.3, semver@^5.1.0, semver@~5.3.0: +"semver@2 || 3 || 4 || 5", semver@^5.0.1, semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@~5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" @@ -3642,7 +3670,7 @@ source-map-loader@0.1.5: loader-utils "~0.2.2" source-map "~0.1.33" -source-map-support@^0.4.0: +source-map-support@^0.4.0, source-map-support@~0.4.0: version "0.4.11" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.11.tgz#647f939978b38535909530885303daf23279f322" dependencies: @@ -3707,10 +3735,6 @@ sshpk@^1.7.0: version "1.3.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" -stealthy-require@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" - stream-browserify@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" @@ -3764,6 +3788,10 @@ strip-bom@^2.0.0: dependencies: is-utf8 "^0.2.0" +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + strip-indent@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" @@ -3806,10 +3834,6 @@ symbol-observable@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d" -symbol-tree@^3.2.1: - version "3.2.2" - resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" - tapable@^0.1.8: version "0.1.10" resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.1.10.tgz#29c35707c2b70e50d07482b5d202e8ed446dafd4" @@ -3873,6 +3897,16 @@ tiny-emitter@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-1.2.0.tgz#6dc845052cb08ebefc1874723b58f24a648c3b6f" +tmp@0.0.24: + version "0.0.24" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.24.tgz#d6a5e198d14a9835cc6f2d7c3d9e302428c8cf12" + +tmp@0.0.30: + version "0.0.30" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" + dependencies: + os-tmpdir "~1.0.1" + tmp@0.0.31, tmp@0.0.x: version "0.0.31" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7" @@ -3893,16 +3927,12 @@ touch@^1.0.0: dependencies: nopt "~1.0.10" -tough-cookie@>=2.3.0, tough-cookie@^2.0.0, tough-cookie@^2.3.2, tough-cookie@~2.3.0: +tough-cookie@^2.0.0, tough-cookie@~2.3.0: version "2.3.2" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" dependencies: punycode "^1.4.1" -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - trim-newlines@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" @@ -3939,6 +3969,21 @@ ts-node@^1.2.1: xtend "^4.0.0" yn "^1.2.0" +ts-node@^3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-3.0.6.tgz#55127ff790c7eebf6ba68c1e6dde94b09aaa21e0" + dependencies: + arrify "^1.0.0" + chalk "^1.1.1" + diff "^3.1.0" + make-error "^1.1.1" + minimist "^1.2.0" + mkdirp "^0.5.1" + source-map-support "^0.4.0" + tsconfig "^6.0.0" + v8flags "^2.0.11" + yn "^2.0.0" + tsconfig@^5.0.2: version "5.0.3" resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-5.0.3.tgz#5f4278e701800967a8fc383fd19648878f2a6e3a" @@ -3948,6 +3993,13 @@ tsconfig@^5.0.2: strip-bom "^2.0.0" strip-json-comments "^2.0.0" +tsconfig@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-6.0.0.tgz#6b0e8376003d7af1864f8df8f89dd0059ffcd032" + dependencies: + strip-bom "^3.0.0" + strip-json-comments "^2.0.0" + tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" @@ -4207,13 +4259,28 @@ wcwidth@^1.0.0: dependencies: defaults "^1.0.3" -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" +webdriver-js-extender@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/webdriver-js-extender/-/webdriver-js-extender-1.0.0.tgz#81c533a9e33d5bfb597b4e63e2cdb25b54777515" + dependencies: + "@types/selenium-webdriver" "^2.53.35" + selenium-webdriver "^2.53.2" -webidl-conversions@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.1.tgz#8015a17ab83e7e1b311638486ace81da6ce206a0" +webdriver-manager@^12.0.6: + version "12.0.6" + resolved "https://registry.yarnpkg.com/webdriver-manager/-/webdriver-manager-12.0.6.tgz#3df1a481977010b4cbf8c9d85c7a577828c0e70b" + dependencies: + adm-zip "^0.4.7" + chalk "^1.1.1" + del "^2.2.0" + glob "^7.0.3" + ini "^1.3.4" + minimist "^1.2.0" + q "^1.4.1" + request "^2.78.0" + rimraf "^2.5.2" + semver "^5.3.0" + xml2js "^0.4.17" webpack-dev-middleware@^1.0.11: version "1.10.1" @@ -4256,19 +4323,6 @@ webpack@^2.2: webpack-sources "^0.1.4" yargs "^6.0.0" -whatwg-encoding@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz#3c6c451a198ee7aec55b1ec61d0920c67801a5f4" - dependencies: - iconv-lite "0.4.13" - -whatwg-url@^4.3.0: - version "4.8.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.8.0.tgz#d2981aa9148c1e00a41c5a6131166ab4683bbcc0" - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - whet.extend@~0.9.9: version "0.9.9" resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1" @@ -4330,7 +4384,7 @@ write-file-atomic@^1.1.2: imurmurhash "^0.1.4" slide "^1.1.5" -ws@1.1.2: +ws@1.1.2, ws@^1.0.1: version "1.1.2" resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.2.tgz#8a244fa052401e08c9886cf44a85189e1fd4067f" dependencies: @@ -4351,9 +4405,25 @@ xml-char-classes@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/xml-char-classes/-/xml-char-classes-1.0.0.tgz#64657848a20ffc5df583a42ad8a277b4512bbc4d" -xml-name-validator@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635" +xml2js@0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.4.tgz#3111010003008ae19240eba17497b57c729c555d" + dependencies: + sax "0.6.x" + xmlbuilder ">=1.0.0" + +xml2js@^0.4.17: + version "0.4.17" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868" + dependencies: + sax ">=0.6.0" + xmlbuilder "^4.1.0" + +xmlbuilder@>=1.0.0, xmlbuilder@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-4.2.1.tgz#aa58a3041a066f90eaa16c2f5389ff19f3f461a5" + dependencies: + lodash "^4.0.0" xmlhttprequest-ssl@1.5.3: version "1.5.3" @@ -4408,6 +4478,10 @@ yn@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/yn/-/yn-1.2.0.tgz#d237a4c533f279b2b89d3acac2db4b8c795e4a63" +yn@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yn/-/yn-2.0.0.tgz#e5adabc8acf408f6385fc76495684c88e6af689a" + zeroclipboard@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/zeroclipboard/-/zeroclipboard-2.3.0.tgz#592ebd833a4308688b0739697d3dbf989002c9af"