diff --git a/package.json b/package.json index be1ab6ea7add..5b1e29d2e9ee 100644 --- a/package.json +++ b/package.json @@ -113,6 +113,7 @@ "husky": "^1.3.1", "inquirer": "^6.2.0", "jasmine-core": "^3.5.0", + "kagekiri": "^1.0.18", "karma": "^4.4.1", "karma-browserstack-launcher": "^1.3.0", "karma-chrome-launcher": "^2.2.0", diff --git a/rollup-globals.bzl b/rollup-globals.bzl index 2f0ae3966c3b..32485f6154a3 100644 --- a/rollup-globals.bzl +++ b/rollup-globals.bzl @@ -69,6 +69,7 @@ ROLLUP_GLOBALS = { "@material/top-app-bar": "mdc.topAppBar", # Third-party libraries. + "kagekiri": "kagekiri", "moment": "moment", "protractor": "protractor", "rxjs": "rxjs", diff --git a/src/cdk/testing/BUILD.bazel b/src/cdk/testing/BUILD.bazel index 3967f007d85c..80855ba75c8c 100644 --- a/src/cdk/testing/BUILD.bazel +++ b/src/cdk/testing/BUILD.bazel @@ -26,7 +26,15 @@ filegroup( ng_web_test_suite( name = "unit_tests", - deps = ["//src/cdk/testing/tests:unit_test_sources"], + # We need to load Kagekiri statically since it is not a named AMD module and needs to + # be manually configured through "require.js" which is used by "karma_web_test_suite". + static_files = [ + "@npm//kagekiri", + ], + deps = [ + ":require-config.js", + "//src/cdk/testing/tests:unit_test_sources", + ], ) e2e_test_suite( diff --git a/src/cdk/testing/protractor/protractor-harness-environment.ts b/src/cdk/testing/protractor/protractor-harness-environment.ts index 4ab26a73f1a2..1ff79296ddd8 100644 --- a/src/cdk/testing/protractor/protractor-harness-environment.ts +++ b/src/cdk/testing/protractor/protractor-harness-environment.ts @@ -7,18 +7,34 @@ */ import {HarnessEnvironment, HarnessLoader, TestElement} from '@angular/cdk/testing'; -import {by, element as protractorElement, ElementFinder} from 'protractor'; +import {by, element as protractorElement, ElementArrayFinder, ElementFinder} from 'protractor'; import {ProtractorElement} from './protractor-element'; +/** Options to configure the environment. */ +export interface ProtractorHarnessEnvironmentOptions { + /** The query function used to find DOM elements. */ + queryFn: (selector: string, root: ElementFinder) => ElementArrayFinder; +} + +/** The default environment options. */ +const defaultEnvironmentOptions: ProtractorHarnessEnvironmentOptions = { + queryFn: (selector: string, root: ElementFinder) => root.all(by.css(selector)) +}; + /** A `HarnessEnvironment` implementation for Protractor. */ export class ProtractorHarnessEnvironment extends HarnessEnvironment { - protected constructor(rawRootElement: ElementFinder) { + /** The options for this environment. */ + private _options: ProtractorHarnessEnvironmentOptions; + + protected constructor( + rawRootElement: ElementFinder, options?: ProtractorHarnessEnvironmentOptions) { super(rawRootElement); + this._options = {...defaultEnvironmentOptions, ...options}; } /** Creates a `HarnessLoader` rooted at the document root. */ - static loader(): HarnessLoader { - return new ProtractorHarnessEnvironment(protractorElement(by.css('body'))); + static loader(options?: ProtractorHarnessEnvironmentOptions): HarnessLoader { + return new ProtractorHarnessEnvironment(protractorElement(by.css('body')), options); } async forceStabilize(): Promise {} @@ -37,15 +53,15 @@ export class ProtractorHarnessEnvironment extends HarnessEnvironment { - return new ProtractorHarnessEnvironment(element); + return new ProtractorHarnessEnvironment(element, this._options); } protected async getAllRawElements(selector: string): Promise { - const elementFinderArray = this.rawRootElement.all(by.css(selector)); - const length = await elementFinderArray.count(); + const elementArrayFinder = this._options.queryFn(selector, this.rawRootElement); + const length = await elementArrayFinder.count(); const elements: ElementFinder[] = []; for (let i = 0; i < length; i++) { - elements.push(elementFinderArray.get(i)); + elements.push(elementArrayFinder.get(i)); } return elements; } diff --git a/src/cdk/testing/require-config.js b/src/cdk/testing/require-config.js new file mode 100644 index 000000000000..af84b376e6eb --- /dev/null +++ b/src/cdk/testing/require-config.js @@ -0,0 +1,7 @@ +// Require.js is being used by the karma bazel rules and needs to be configured to properly +// load AMD modules which are not explicitly named in their output bundle. +require.config({ + paths: { + 'kagekiri': '/base/npm/node_modules/kagekiri/dist/kagekiri.umd.min', + } +}); diff --git a/src/cdk/testing/testbed/testbed-harness-environment.ts b/src/cdk/testing/testbed/testbed-harness-environment.ts index c5c3cb4d5aad..52d423601c69 100644 --- a/src/cdk/testing/testbed/testbed-harness-environment.ts +++ b/src/cdk/testing/testbed/testbed-harness-environment.ts @@ -19,31 +19,49 @@ import {takeWhile} from 'rxjs/operators'; import {TaskState, TaskStateZoneInterceptor} from './task-state-zone-interceptor'; import {UnitTestElement} from './unit-test-element'; +/** Options to configure the environment. */ +export interface TestbedHarnessEnvironmentOptions { + /** The query function used to find DOM elements. */ + queryFn: (selector: string, root: Element) => Iterable | ArrayLike; +} + +/** The default environment options. */ +const defaultEnvironmentOptions: TestbedHarnessEnvironmentOptions = { + queryFn: (selector: string, root: Element) => root.querySelectorAll(selector) +}; /** A `HarnessEnvironment` implementation for Angular's Testbed. */ export class TestbedHarnessEnvironment extends HarnessEnvironment { + /** Whether the environment has been destroyed. */ private _destroyed = false; /** Observable that emits whenever the test task state changes. */ private _taskState: Observable; - protected constructor(rawRootElement: Element, private _fixture: ComponentFixture) { + /** The options for this environment. */ + private _options: TestbedHarnessEnvironmentOptions; + + protected constructor(rawRootElement: Element, private _fixture: ComponentFixture, + options?: TestbedHarnessEnvironmentOptions) { super(rawRootElement); + this._options = {...defaultEnvironmentOptions, ...options}; this._taskState = TaskStateZoneInterceptor.setup(); _fixture.componentRef.onDestroy(() => this._destroyed = true); } /** Creates a `HarnessLoader` rooted at the given fixture's root element. */ - static loader(fixture: ComponentFixture): HarnessLoader { - return new TestbedHarnessEnvironment(fixture.nativeElement, fixture); + static loader(fixture: ComponentFixture, options?: TestbedHarnessEnvironmentOptions): + HarnessLoader { + return new TestbedHarnessEnvironment(fixture.nativeElement, fixture, options); } /** * Creates a `HarnessLoader` at the document root. This can be used if harnesses are * located outside of a fixture (e.g. overlays appended to the document body). */ - static documentRootLoader(fixture: ComponentFixture): HarnessLoader { - return new TestbedHarnessEnvironment(document.body, fixture); + static documentRootLoader(fixture: ComponentFixture, + options?: TestbedHarnessEnvironmentOptions): HarnessLoader { + return new TestbedHarnessEnvironment(document.body, fixture, options); } /** @@ -53,8 +71,9 @@ export class TestbedHarnessEnvironment extends HarnessEnvironment { * of the fixture. */ static async harnessForFixture( - fixture: ComponentFixture, harnessType: ComponentHarnessConstructor): Promise { - const environment = new TestbedHarnessEnvironment(fixture.nativeElement, fixture); + fixture: ComponentFixture, harnessType: ComponentHarnessConstructor, + options?: TestbedHarnessEnvironmentOptions): Promise { + const environment = new TestbedHarnessEnvironment(fixture.nativeElement, fixture, options); await environment.forceStabilize(); return environment.createComponentHarness(harnessType, fixture.nativeElement); } @@ -95,11 +114,11 @@ export class TestbedHarnessEnvironment extends HarnessEnvironment { } protected createEnvironment(element: Element): HarnessEnvironment { - return new TestbedHarnessEnvironment(element, this._fixture); + return new TestbedHarnessEnvironment(element, this._fixture, this._options); } protected async getAllRawElements(selector: string): Promise { await this.forceStabilize(); - return Array.from(this.rawRootElement.querySelectorAll(selector)); + return Array.from(this._options.queryFn(selector, this.rawRootElement)); } } diff --git a/src/cdk/testing/tests/BUILD.bazel b/src/cdk/testing/tests/BUILD.bazel index f1d088e7c86f..f845b0981c5c 100644 --- a/src/cdk/testing/tests/BUILD.bazel +++ b/src/cdk/testing/tests/BUILD.bazel @@ -9,12 +9,14 @@ ng_module( ["**/*.ts"], exclude = [ "**/*.spec.ts", + "**/*.spec.d.ts", "harnesses/**", ], ), assets = glob(["**/*.html"]), deps = [ "//src/cdk/keycodes", + "//src/cdk/platform", "@npm//@angular/forms", ], ) @@ -30,22 +32,30 @@ ts_library( ng_test_library( name = "unit_test_sources", srcs = glob( - ["**/*.spec.ts"], + [ + "**/*.spec.ts", + "**/*.spec.d.ts", + ], exclude = ["**/*.e2e.spec.ts"], ), deps = [ ":test_components", ":test_harnesses", + "//src/cdk/platform", "//src/cdk/testing", "//src/cdk/testing/private", "//src/cdk/testing/testbed", "@npm//@angular/platform-browser", + "@npm//kagekiri", ], ) ng_e2e_test_library( name = "e2e_test_sources", - srcs = glob(["**/*.e2e.spec.ts"]), + srcs = glob([ + "**/*.e2e.spec.ts", + "**/*.spec.d.ts", + ]), deps = [ ":test_harnesses", "//src/cdk/testing", diff --git a/src/cdk/testing/tests/harnesses/main-component-harness.ts b/src/cdk/testing/tests/harnesses/main-component-harness.ts index 5ccf385b0c20..4694f8297b66 100644 --- a/src/cdk/testing/tests/harnesses/main-component-harness.ts +++ b/src/cdk/testing/tests/harnesses/main-component-harness.ts @@ -81,6 +81,9 @@ export class MainComponentHarness extends ComponentHarness { this.locatorForAll(SubComponentHarness, SubComponentSpecialHarness); readonly missingElementsAndHarnesses = this.locatorFor('.not-found', SubComponentHarness.with({title: /not found/})); + readonly shadows = this.locatorForAll('.in-the-shadows'); + readonly deepShadow = this.locatorFor( + 'test-shadow-boundary test-sub-shadow-boundary > .in-the-shadows'); private _testTools = this.locatorFor(SubComponentHarness); diff --git a/src/cdk/testing/tests/kagekiri.spec.d.ts b/src/cdk/testing/tests/kagekiri.spec.d.ts new file mode 100644 index 000000000000..bfa43c5ae493 --- /dev/null +++ b/src/cdk/testing/tests/kagekiri.spec.d.ts @@ -0,0 +1,13 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +// Note: kagekiri is a dev dependency that is used only in our tests to test using a custom +// querySelector function. Do not use this in published code. +declare module 'kagekiri' { + export function querySelectorAll(selector: string, root: Element): NodeListOf; +} diff --git a/src/cdk/testing/tests/protractor.e2e.spec.ts b/src/cdk/testing/tests/protractor.e2e.spec.ts index 15bb9708f75f..bb8da1d692cd 100644 --- a/src/cdk/testing/tests/protractor.e2e.spec.ts +++ b/src/cdk/testing/tests/protractor.e2e.spec.ts @@ -5,10 +5,21 @@ import { TestElement } from '@angular/cdk/testing'; import {ProtractorHarnessEnvironment} from '@angular/cdk/testing/protractor'; -import {browser} from 'protractor'; +import {browser, by, element as protractorElement, ElementFinder} from 'protractor'; import {MainComponentHarness} from './harnesses/main-component-harness'; import {SubComponentHarness, SubComponentSpecialHarness} from './harnesses/sub-component-harness'; +// Kagekiri is available globally in the browser. We declare it here so we can use it in the +// browser-side script passed to `by.js`. +// TODO(mmalerba): Replace with type-only import once TS 3.8 is available, see: +// https://devblogs.microsoft.com/typescript/announcing-typescript-3-8-beta/#type-only-imports-exports +declare const kagekiri: { + querySelectorAll: (selector: string, root: Element) => NodeListOf; +}; + +const piercingQueryFn = (selector: string, root: ElementFinder) => protractorElement.all(by.js( + (s: string, r: Element) => kagekiri.querySelectorAll(s, r), selector, root.getWebElement())); + describe('ProtractorHarnessEnvironment', () => { beforeEach(async () => { await browser.get('/component-harness'); @@ -460,6 +471,27 @@ describe('ProtractorHarnessEnvironment', () => { } }); }); + + describe('shadow DOM interaction', () => { + it('should not pierce shadow boundary by default', async () => { + const harness = await ProtractorHarnessEnvironment.loader() + .getHarness(MainComponentHarness); + expect(await harness.shadows()).toEqual([]); + }); + + it('should pierce shadow boundary when using piercing query', async () => { + const harness = await ProtractorHarnessEnvironment.loader({queryFn: piercingQueryFn}) + .getHarness(MainComponentHarness); + const shadows = await harness.shadows(); + expect(await Promise.all(shadows.map(el => el.text()))).toEqual(['Shadow 1', 'Shadow 2']); + }); + + it('should allow querying across shadow boundary', async () => { + const harness = await ProtractorHarnessEnvironment.loader({queryFn: piercingQueryFn}) + .getHarness(MainComponentHarness); + expect(await (await harness.deepShadow()).text()).toBe('Shadow 2'); + }); + }); }); async function checkIsElement(result: ComponentHarness | TestElement, selector?: string) { diff --git a/src/cdk/testing/tests/test-components-module.ts b/src/cdk/testing/tests/test-components-module.ts index 045c8633cbc7..10cef6eeaad7 100644 --- a/src/cdk/testing/tests/test-components-module.ts +++ b/src/cdk/testing/tests/test-components-module.ts @@ -10,11 +10,12 @@ import {CommonModule} from '@angular/common'; import {NgModule} from '@angular/core'; import {FormsModule} from '@angular/forms'; import {TestMainComponent} from './test-main-component'; +import {TestShadowBoundary, TestSubShadowBoundary} from './test-shadow-boundary'; import {TestSubComponent} from './test-sub-component'; @NgModule({ imports: [CommonModule, FormsModule], - declarations: [TestMainComponent, TestSubComponent], - exports: [TestMainComponent, TestSubComponent] + declarations: [TestMainComponent, TestSubComponent, TestShadowBoundary, TestSubShadowBoundary], + exports: [TestMainComponent, TestSubComponent, TestShadowBoundary, TestSubShadowBoundary] }) export class TestComponentsModule {} diff --git a/src/cdk/testing/tests/test-main-component.html b/src/cdk/testing/tests/test-main-component.html index c57442de2a26..99998b6b0670 100644 --- a/src/cdk/testing/tests/test-main-component.html +++ b/src/cdk/testing/tests/test-main-component.html @@ -32,4 +32,4 @@

Main Component

- + diff --git a/src/cdk/testing/tests/test-main-component.ts b/src/cdk/testing/tests/test-main-component.ts index 32c18182b0af..2c4d9fd551bb 100644 --- a/src/cdk/testing/tests/test-main-component.ts +++ b/src/cdk/testing/tests/test-main-component.ts @@ -7,6 +7,7 @@ */ import {ENTER} from '@angular/cdk/keycodes'; +import {_supportsShadowDom} from '@angular/cdk/platform'; import { ChangeDetectionStrategy, ChangeDetectorRef, @@ -42,6 +43,7 @@ export class TestMainComponent implements OnDestroy { specialKey = ''; relativeX = 0; relativeY = 0; + _shadowDomSupported = _supportsShadowDom(); @ViewChild('clickTestElement') clickTestElement: ElementRef; @ViewChild('taskStateResult') taskStateResultElement: ElementRef; diff --git a/src/cdk/testing/tests/test-shadow-boundary.ts b/src/cdk/testing/tests/test-shadow-boundary.ts new file mode 100644 index 000000000000..ee7cb1d0616d --- /dev/null +++ b/src/cdk/testing/tests/test-shadow-boundary.ts @@ -0,0 +1,30 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {ChangeDetectionStrategy, Component, ViewEncapsulation} from '@angular/core'; + +@Component({ + selector: 'test-shadow-boundary', + template: ` +
Shadow 1
+ + `, + changeDetection: ChangeDetectionStrategy.OnPush, + // tslint:disable-next-line:validate-decorators + encapsulation: ViewEncapsulation.ShadowDom, +}) +export class TestShadowBoundary {} + +@Component({ + selector: 'test-sub-shadow-boundary', + template: '
Shadow 2
', + changeDetection: ChangeDetectionStrategy.OnPush, + // tslint:disable-next-line:validate-decorators + encapsulation: ViewEncapsulation.ShadowDom, +}) +export class TestSubShadowBoundary {} diff --git a/src/cdk/testing/tests/testbed.spec.ts b/src/cdk/testing/tests/testbed.spec.ts index 8caa1b293212..59854ff67cbe 100644 --- a/src/cdk/testing/tests/testbed.spec.ts +++ b/src/cdk/testing/tests/testbed.spec.ts @@ -1,3 +1,4 @@ +import {_supportsShadowDom} from '@angular/cdk/platform'; import { ComponentHarness, ComponentHarnessConstructor, @@ -6,6 +7,7 @@ import { } from '@angular/cdk/testing'; import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed'; import {async, ComponentFixture, fakeAsync, TestBed} from '@angular/core/testing'; +import {querySelectorAll as piercingQuerySelectorAll} from 'kagekiri'; import {FakeOverlayHarness} from './harnesses/fake-overlay-harness'; import {MainComponentHarness} from './harnesses/main-component-harness'; import {SubComponentHarness, SubComponentSpecialHarness} from './harnesses/sub-component-harness'; @@ -504,6 +506,29 @@ describe('TestbedHarnessEnvironment', () => { } }); }); + + if (_supportsShadowDom()) { + describe('shadow DOM interaction', () => { + it('should not pierce shadow boundary by default', async () => { + const harness = await TestbedHarnessEnvironment + .harnessForFixture(fixture, MainComponentHarness); + expect(await harness.shadows()).toEqual([]); + }); + + it('should pierce shadow boundary when using piercing query', async () => { + const harness = await TestbedHarnessEnvironment + .harnessForFixture(fixture, MainComponentHarness, {queryFn: piercingQuerySelectorAll}); + const shadows = await harness.shadows(); + expect(await Promise.all(shadows.map(el => el.text()))).toEqual(['Shadow 1', 'Shadow 2']); + }); + + it('should allow querying across shadow boundary', async () => { + const harness = await TestbedHarnessEnvironment + .harnessForFixture(fixture, MainComponentHarness, {queryFn: piercingQuerySelectorAll}); + expect(await (await harness.deepShadow()).text()).toBe('Shadow 2'); + }); + }); + } }); async function checkIsElement(result: ComponentHarness | TestElement, selector?: string) { diff --git a/src/e2e-app/BUILD.bazel b/src/e2e-app/BUILD.bazel index 12e22b114f1d..184cd887aa64 100644 --- a/src/e2e-app/BUILD.bazel +++ b/src/e2e-app/BUILD.bazel @@ -102,6 +102,7 @@ ts_devserver( static_files = [ "@npm//zone.js", "@npm//core-js", + "@npm//kagekiri", "@npm//material-components-web", "@npm//moment", "@npm//@webcomponents/custom-elements", diff --git a/src/e2e-app/index.html b/src/e2e-app/index.html index 79483f0eea7f..0c0c2844f426 100644 --- a/src/e2e-app/index.html +++ b/src/e2e-app/index.html @@ -29,6 +29,7 @@ + diff --git a/test/karma.conf.js b/test/karma.conf.js index 3bdb13efd165..bc8006e55515 100644 --- a/test/karma.conf.js +++ b/test/karma.conf.js @@ -45,6 +45,7 @@ module.exports = config => { watched: false }, {pattern: 'node_modules/@material/*/dist/*', included: false, watched: false}, + {pattern: 'node_modules/kagekiri/**', included: false, watched: false}, // Include all Angular dependencies {pattern: 'node_modules/@angular/**/*', included: false, watched: false}, diff --git a/tools/public_api_guard/cdk/testing/protractor.d.ts b/tools/public_api_guard/cdk/testing/protractor.d.ts index a1e105b81cf0..0761944d3d74 100644 --- a/tools/public_api_guard/cdk/testing/protractor.d.ts +++ b/tools/public_api_guard/cdk/testing/protractor.d.ts @@ -19,12 +19,16 @@ export declare class ProtractorElement implements TestElement { } export declare class ProtractorHarnessEnvironment extends HarnessEnvironment { - protected constructor(rawRootElement: ElementFinder); + protected constructor(rawRootElement: ElementFinder, options?: ProtractorHarnessEnvironmentOptions); protected createEnvironment(element: ElementFinder): HarnessEnvironment; protected createTestElement(element: ElementFinder): TestElement; forceStabilize(): Promise; protected getAllRawElements(selector: string): Promise; protected getDocumentRoot(): ElementFinder; waitForTasksOutsideAngular(): Promise; - static loader(): HarnessLoader; + static loader(options?: ProtractorHarnessEnvironmentOptions): HarnessLoader; +} + +export interface ProtractorHarnessEnvironmentOptions { + queryFn: (selector: string, root: ElementFinder) => ElementArrayFinder; } diff --git a/tools/public_api_guard/cdk/testing/testbed.d.ts b/tools/public_api_guard/cdk/testing/testbed.d.ts index d2572ad5cf17..a44594f0b0ef 100644 --- a/tools/public_api_guard/cdk/testing/testbed.d.ts +++ b/tools/public_api_guard/cdk/testing/testbed.d.ts @@ -1,14 +1,18 @@ export declare class TestbedHarnessEnvironment extends HarnessEnvironment { - protected constructor(rawRootElement: Element, _fixture: ComponentFixture); + protected constructor(rawRootElement: Element, _fixture: ComponentFixture, options?: TestbedHarnessEnvironmentOptions); protected createEnvironment(element: Element): HarnessEnvironment; protected createTestElement(element: Element): TestElement; forceStabilize(): Promise; protected getAllRawElements(selector: string): Promise; protected getDocumentRoot(): Element; waitForTasksOutsideAngular(): Promise; - static documentRootLoader(fixture: ComponentFixture): HarnessLoader; - static harnessForFixture(fixture: ComponentFixture, harnessType: ComponentHarnessConstructor): Promise; - static loader(fixture: ComponentFixture): HarnessLoader; + static documentRootLoader(fixture: ComponentFixture, options?: TestbedHarnessEnvironmentOptions): HarnessLoader; + static harnessForFixture(fixture: ComponentFixture, harnessType: ComponentHarnessConstructor, options?: TestbedHarnessEnvironmentOptions): Promise; + static loader(fixture: ComponentFixture, options?: TestbedHarnessEnvironmentOptions): HarnessLoader; +} + +export interface TestbedHarnessEnvironmentOptions { + queryFn: (selector: string, root: Element) => Iterable | ArrayLike; } export declare class UnitTestElement implements TestElement { diff --git a/tools/system-config-tmpl.js b/tools/system-config-tmpl.js index 33dbe96511f7..6e8cdae10997 100644 --- a/tools/system-config-tmpl.js +++ b/tools/system-config-tmpl.js @@ -31,6 +31,7 @@ var nodeModulesPath = '$NODE_MODULES_BASE_PATH'; var pathMapping = { 'tslib': 'node:tslib/tslib.js', 'moment': 'node:moment/min/moment-with-locales.min.js', + 'kagekiri': 'node:kagekiri/dist/kagekiri.umd.min.js', 'rxjs': 'node:rxjs/bundles/rxjs.umd.min.js', 'rxjs/operators': 'tools/system-rxjs-operators.js', diff --git a/tslint.json b/tslint.json index e085c84e39d7..dc603b940244 100644 --- a/tslint.json +++ b/tslint.json @@ -8,7 +8,8 @@ "max-line-length": [true, { "limit": 100, "check-strings": true, - "check-regex": true + "check-regex": true, + "ignore-pattern": "//\\s+https?://" } ], // Disable this flag because of SHA tslint#48b0c597f9257712c7d1f04b55ed0aa60e333f6a diff --git a/yarn.lock b/yarn.lock index 7445ff9af27b..b644a9a29aba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6719,6 +6719,11 @@ jws@^3.0.0, jws@^3.1.4, jws@^3.1.5: jwa "^1.1.5" safe-buffer "^5.0.1" +kagekiri@^1.0.18: + version "1.0.18" + resolved "https://registry.yarnpkg.com/kagekiri/-/kagekiri-1.0.18.tgz#4400714f37d79e7ec80c99aa5a0a59f729c1a6a7" + integrity sha512-J0dcWXcdzMDBOm3YE5sljkPfAHenv9zELJhjlfo/mxe98CtaaIXbC9JIjOfLk8m4B9hiATmkm5vBaBPrOOSbAQ== + karma-browserstack-launcher@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/karma-browserstack-launcher/-/karma-browserstack-launcher-1.3.0.tgz#61fe3d36b1cf10681e40f9d874bf37271fb1c674"