cypress 13.2.0 → 13.3.1
Sign up to get free protection for your applications and to get access to all the features.
- package/angular/angular/README.md +10 -0
- package/angular/angular/dist/index.d.ts +128 -0
- package/angular/angular/dist/index.js +333 -0
- package/angular/angular/package.json +77 -0
- package/angular/package.json +9 -1
- package/lib/exec/spawn.js +1 -1
- package/lib/util.js +1 -1
- package/mount-utils/mount-utils/README.md +140 -0
- package/mount-utils/mount-utils/dist/index.d.ts +40 -0
- package/mount-utils/mount-utils/dist/index.js +68 -0
- package/mount-utils/mount-utils/package.json +46 -0
- package/mount-utils/package.json +10 -1
- package/package.json +20 -4
- package/react/package.json +13 -0
- package/react/react/README.md +14 -0
- package/react/react/dist/cypress-react.cjs.js +943 -0
- package/react/react/dist/cypress-react.esm-bundler.js +917 -0
- package/react/react/dist/index.d.ts +111 -0
- package/react/react/package.json +111 -0
- package/react18/package.json +10 -0
- package/react18/react18/README.md +7 -0
- package/react18/react18/dist/cypress-react.cjs.js +592 -0
- package/react18/react18/dist/cypress-react.esm-bundler.js +569 -0
- package/react18/react18/dist/index.d.ts +78 -0
- package/react18/react18/package.json +71 -0
- package/svelte/package.json +13 -1
- package/svelte/svelte/README.md +15 -0
- package/svelte/svelte/dist/cypress-svelte.cjs.js +122 -0
- package/svelte/svelte/dist/cypress-svelte.esm-bundler.js +120 -0
- package/svelte/svelte/dist/index.d.ts +201 -0
- package/svelte/svelte/package.json +56 -0
- package/types/cypress.d.ts +2 -2
- package/vue/package.json +13 -1
- package/vue/vue/README.md +14 -0
- package/vue/vue/dist/cypress-vue.cjs.js +8582 -0
- package/vue/vue/dist/cypress-vue.esm-bundler.js +8560 -0
- package/vue/vue/dist/index.d.ts +1392 -0
- package/vue/vue/package.json +96 -0
- package/vue2/dist/cypress-vue2.cjs.js +1 -1
- package/vue2/dist/cypress-vue2.esm-bundler.js +1 -1
- package/vue2/package.json +13 -1
- package/vue2/vue2/README.md +7 -0
- package/vue2/vue2/dist/cypress-vue2.cjs.js +20045 -0
- package/vue2/vue2/dist/cypress-vue2.esm-bundler.js +20042 -0
- package/vue2/vue2/dist/index.d.ts +364 -0
- package/vue2/vue2/package.json +65 -0
@@ -0,0 +1,10 @@
|
|
1
|
+
# @cypress/angular
|
2
|
+
|
3
|
+
Mount Angular components in the open source [Cypress.io](https://www.cypress.io/) test runner
|
4
|
+
|
5
|
+
> **Note:** This package is bundled with the `cypress` package and should not need to be installed separately. See the [Angular Component Testing Docs](https://docs.cypress.io/guides/component-testing/angular/overview) for mounting Angular components. Installing and importing `mount` from `@cypress/angular` should only be done for advanced use-cases.
|
6
|
+
## Development
|
7
|
+
|
8
|
+
Run `yarn build` to compile and sync packages to the `cypress` cli package.
|
9
|
+
|
10
|
+
## [Changelog](./CHANGELOG.md)
|
@@ -0,0 +1,128 @@
|
|
1
|
+
/// <reference types="cypress" />
|
2
|
+
|
3
|
+
import { Type } from '@angular/core';
|
4
|
+
import { TestModuleMetadata, ComponentFixture, TestComponentRenderer } from '@angular/core/testing';
|
5
|
+
|
6
|
+
/**
|
7
|
+
* Additional module configurations needed while mounting the component, like
|
8
|
+
* providers, declarations, imports and even component @Inputs()
|
9
|
+
*
|
10
|
+
*
|
11
|
+
* @interface MountConfig
|
12
|
+
* @see https://angular.io/api/core/testing/TestModuleMetadata
|
13
|
+
*/
|
14
|
+
interface MountConfig<T> extends TestModuleMetadata {
|
15
|
+
/**
|
16
|
+
* @memberof MountConfig
|
17
|
+
* @description flag to automatically create a cy.spy() for every component @Output() property
|
18
|
+
* @example
|
19
|
+
* export class ButtonComponent {
|
20
|
+
* @Output clicked = new EventEmitter()
|
21
|
+
* }
|
22
|
+
*
|
23
|
+
* cy.mount(ButtonComponent, { autoSpyOutputs: true })
|
24
|
+
* cy.get('@clickedSpy).should('have.been.called')
|
25
|
+
*/
|
26
|
+
autoSpyOutputs?: boolean;
|
27
|
+
/**
|
28
|
+
* @memberof MountConfig
|
29
|
+
* @description flag defaulted to true to automatically detect changes in your components
|
30
|
+
*/
|
31
|
+
autoDetectChanges?: boolean;
|
32
|
+
/**
|
33
|
+
* @memberof MountConfig
|
34
|
+
* @example
|
35
|
+
* import { ButtonComponent } from 'button/button.component'
|
36
|
+
* it('renders a button with Save text', () => {
|
37
|
+
* cy.mount(ButtonComponent, { componentProperties: { text: 'Save' }})
|
38
|
+
* cy.get('button').contains('Save')
|
39
|
+
* })
|
40
|
+
*
|
41
|
+
* it('renders a button with a cy.spy() replacing EventEmitter', () => {
|
42
|
+
* cy.mount(ButtonComponent, {
|
43
|
+
* componentProperties: {
|
44
|
+
* clicked: cy.spy().as('mySpy)
|
45
|
+
* }
|
46
|
+
* })
|
47
|
+
* cy.get('button').click()
|
48
|
+
* cy.get('@mySpy').should('have.been.called')
|
49
|
+
* })
|
50
|
+
*/
|
51
|
+
componentProperties?: Partial<{
|
52
|
+
[P in keyof T]: T[P];
|
53
|
+
}>;
|
54
|
+
}
|
55
|
+
/**
|
56
|
+
* Type that the `mount` function returns
|
57
|
+
* @type MountResponse<T>
|
58
|
+
*/
|
59
|
+
declare type MountResponse<T> = {
|
60
|
+
/**
|
61
|
+
* Fixture for debugging and testing a component.
|
62
|
+
*
|
63
|
+
* @memberof MountResponse
|
64
|
+
* @see https://angular.io/api/core/testing/ComponentFixture
|
65
|
+
*/
|
66
|
+
fixture: ComponentFixture<T>;
|
67
|
+
/**
|
68
|
+
* The instance of the root component class
|
69
|
+
*
|
70
|
+
* @memberof MountResponse
|
71
|
+
* @see https://angular.io/api/core/testing/ComponentFixture#componentInstance
|
72
|
+
*/
|
73
|
+
component: T;
|
74
|
+
};
|
75
|
+
declare class CypressTestComponentRenderer extends TestComponentRenderer {
|
76
|
+
insertRootElement(rootElId: string): void;
|
77
|
+
removeAllRootElements(): void;
|
78
|
+
}
|
79
|
+
/**
|
80
|
+
* Mounts an Angular component inside Cypress browser
|
81
|
+
*
|
82
|
+
* @param component Angular component being mounted or its template
|
83
|
+
* @param config configuration used to configure the TestBed
|
84
|
+
* @example
|
85
|
+
* import { mount } from '@cypress/angular'
|
86
|
+
* import { StepperComponent } from './stepper.component'
|
87
|
+
* import { MyService } from 'services/my.service'
|
88
|
+
* import { SharedModule } from 'shared/shared.module';
|
89
|
+
* it('mounts', () => {
|
90
|
+
* mount(StepperComponent, {
|
91
|
+
* providers: [MyService],
|
92
|
+
* imports: [SharedModule]
|
93
|
+
* })
|
94
|
+
* cy.get('[data-cy=increment]').click()
|
95
|
+
* cy.get('[data-cy=counter]').should('have.text', '1')
|
96
|
+
* })
|
97
|
+
*
|
98
|
+
* // or
|
99
|
+
*
|
100
|
+
* it('mounts with template', () => {
|
101
|
+
* mount('<app-stepper></app-stepper>', {
|
102
|
+
* declarations: [StepperComponent],
|
103
|
+
* })
|
104
|
+
* })
|
105
|
+
*
|
106
|
+
* @see {@link https://on.cypress.io/mounting-angular} for more details.
|
107
|
+
*
|
108
|
+
* @returns A component and component fixture
|
109
|
+
*/
|
110
|
+
declare function mount<T>(component: Type<T> | string, config?: MountConfig<T>): Cypress.Chainable<MountResponse<T>>;
|
111
|
+
/**
|
112
|
+
* Creates a new Event Emitter and then spies on it's `emit` method
|
113
|
+
*
|
114
|
+
* @param {string} alias name you want to use for your cy.spy() alias
|
115
|
+
* @returns EventEmitter<T>
|
116
|
+
* @example
|
117
|
+
* import { StepperComponent } from './stepper.component'
|
118
|
+
* import { mount, createOutputSpy } from '@cypress/angular'
|
119
|
+
*
|
120
|
+
* it('Has spy', () => {
|
121
|
+
* mount(StepperComponent, { componentProperties: { change: createOutputSpy('changeSpy') } })
|
122
|
+
* cy.get('[data-cy=increment]').click()
|
123
|
+
* cy.get('@changeSpy').should('have.been.called')
|
124
|
+
* })
|
125
|
+
*/
|
126
|
+
declare const createOutputSpy: <T>(alias: string) => any;
|
127
|
+
|
128
|
+
export { CypressTestComponentRenderer, MountConfig, MountResponse, createOutputSpy, mount };
|
@@ -0,0 +1,333 @@
|
|
1
|
+
|
2
|
+
/**
|
3
|
+
* @cypress/angular v0.0.0-development
|
4
|
+
* (c) 2023 Cypress.io
|
5
|
+
* Released under the MIT License
|
6
|
+
*/
|
7
|
+
|
8
|
+
import 'zone.js';
|
9
|
+
import 'zone.js/testing';
|
10
|
+
import { CommonModule } from '@angular/common';
|
11
|
+
import { Injectable, Component, EventEmitter, SimpleChange, ErrorHandler } from '@angular/core';
|
12
|
+
import { getTestBed, TestComponentRenderer, TestBed } from '@angular/core/testing';
|
13
|
+
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
14
|
+
|
15
|
+
/******************************************************************************
|
16
|
+
Copyright (c) Microsoft Corporation.
|
17
|
+
|
18
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
19
|
+
purpose with or without fee is hereby granted.
|
20
|
+
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
22
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
23
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
24
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
25
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
26
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
27
|
+
PERFORMANCE OF THIS SOFTWARE.
|
28
|
+
***************************************************************************** */
|
29
|
+
|
30
|
+
function __rest(s, e) {
|
31
|
+
var t = {};
|
32
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
33
|
+
t[p] = s[p];
|
34
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
35
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
36
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
37
|
+
t[p[i]] = s[p[i]];
|
38
|
+
}
|
39
|
+
return t;
|
40
|
+
}
|
41
|
+
|
42
|
+
function __decorate(decorators, target, key, desc) {
|
43
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
44
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
45
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
46
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
47
|
+
}
|
48
|
+
|
49
|
+
const ROOT_SELECTOR = '[data-cy-root]';
|
50
|
+
/**
|
51
|
+
* Gets the root element used to mount the component.
|
52
|
+
* @returns {HTMLElement} The root element
|
53
|
+
* @throws {Error} If the root element is not found
|
54
|
+
*/
|
55
|
+
const getContainerEl = () => {
|
56
|
+
const el = document.querySelector(ROOT_SELECTOR);
|
57
|
+
if (el) {
|
58
|
+
return el;
|
59
|
+
}
|
60
|
+
throw Error(`No element found that matches selector ${ROOT_SELECTOR}. Please add a root element with data-cy-root attribute to your "component-index.html" file so that Cypress can attach your component to the DOM.`);
|
61
|
+
};
|
62
|
+
/**
|
63
|
+
* Utility function to register CT side effects and run cleanup code during the "test:before:run" Cypress hook
|
64
|
+
* @param optionalCallback Callback to be called before the next test runs
|
65
|
+
*/
|
66
|
+
function setupHooks(optionalCallback) {
|
67
|
+
// We don't want CT side effects to run when e2e
|
68
|
+
// testing so we early return.
|
69
|
+
// System test to verify CT side effects do not pollute e2e: system-tests/test/e2e_with_mount_import_spec.ts
|
70
|
+
if (Cypress.testingType !== 'component') {
|
71
|
+
return;
|
72
|
+
}
|
73
|
+
// When running component specs, we cannot allow "cy.visit"
|
74
|
+
// because it will wipe out our preparation work, and does not make much sense
|
75
|
+
// thus we overwrite "cy.visit" to throw an error
|
76
|
+
Cypress.Commands.overwrite('visit', () => {
|
77
|
+
throw new Error('cy.visit from a component spec is not allowed');
|
78
|
+
});
|
79
|
+
Cypress.Commands.overwrite('session', () => {
|
80
|
+
throw new Error('cy.session from a component spec is not allowed');
|
81
|
+
});
|
82
|
+
Cypress.Commands.overwrite('origin', () => {
|
83
|
+
throw new Error('cy.origin from a component spec is not allowed');
|
84
|
+
});
|
85
|
+
// @ts-ignore
|
86
|
+
Cypress.on('test:before:after:run:async', () => {
|
87
|
+
optionalCallback === null || optionalCallback === void 0 ? void 0 : optionalCallback();
|
88
|
+
});
|
89
|
+
}
|
90
|
+
|
91
|
+
/**
|
92
|
+
* @hack fixes "Mocha has already been patched with Zone" error.
|
93
|
+
*/
|
94
|
+
// @ts-ignore
|
95
|
+
window.Mocha['__zone_patch__'] = false;
|
96
|
+
let activeFixture = null;
|
97
|
+
function cleanup() {
|
98
|
+
// Not public, we need to call this to remove the last component from the DOM
|
99
|
+
try {
|
100
|
+
getTestBed().tearDownTestingModule();
|
101
|
+
}
|
102
|
+
catch (e) {
|
103
|
+
const notSupportedError = new Error(`Failed to teardown component. The version of Angular you are using may not be officially supported.`);
|
104
|
+
notSupportedError.docsUrl = 'https://on.cypress.io/component-framework-configuration';
|
105
|
+
throw notSupportedError;
|
106
|
+
}
|
107
|
+
getTestBed().resetTestingModule();
|
108
|
+
activeFixture = null;
|
109
|
+
}
|
110
|
+
// 'zone.js/testing' is not properly aliasing `it.skip` but it does provide `xit`/`xspecify`
|
111
|
+
// Written up under https://github.com/angular/angular/issues/46297 but is not seeing movement
|
112
|
+
// so we'll patch here pending a fix in that library
|
113
|
+
// @ts-ignore Ignore so that way we can bypass semantic error TS7017: Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature.
|
114
|
+
globalThis.it.skip = globalThis.xit;
|
115
|
+
let CypressAngularErrorHandler = class CypressAngularErrorHandler {
|
116
|
+
handleError(error) {
|
117
|
+
throw error;
|
118
|
+
}
|
119
|
+
};
|
120
|
+
CypressAngularErrorHandler = __decorate([
|
121
|
+
Injectable()
|
122
|
+
], CypressAngularErrorHandler);
|
123
|
+
/**
|
124
|
+
* Bootstraps the TestModuleMetaData passed to the TestBed
|
125
|
+
*
|
126
|
+
* @param {Type<T>} component Angular component being mounted
|
127
|
+
* @param {MountConfig} config TestBed configuration passed into the mount function
|
128
|
+
* @returns {MountConfig} MountConfig
|
129
|
+
*/
|
130
|
+
function bootstrapModule(component, config) {
|
131
|
+
var _a;
|
132
|
+
const testModuleMetaData = __rest(config, ["componentProperties"]);
|
133
|
+
if (!testModuleMetaData.declarations) {
|
134
|
+
testModuleMetaData.declarations = [];
|
135
|
+
}
|
136
|
+
if (!testModuleMetaData.imports) {
|
137
|
+
testModuleMetaData.imports = [];
|
138
|
+
}
|
139
|
+
if (!testModuleMetaData.providers) {
|
140
|
+
testModuleMetaData.providers = [];
|
141
|
+
}
|
142
|
+
// Replace default error handler since it will swallow uncaught exceptions.
|
143
|
+
// We want these to be uncaught so Cypress catches it and fails the test
|
144
|
+
testModuleMetaData.providers.push({
|
145
|
+
provide: ErrorHandler,
|
146
|
+
useClass: CypressAngularErrorHandler,
|
147
|
+
});
|
148
|
+
// check if the component is a standalone component
|
149
|
+
if ((_a = component.ɵcmp) === null || _a === void 0 ? void 0 : _a.standalone) {
|
150
|
+
testModuleMetaData.imports.push(component);
|
151
|
+
}
|
152
|
+
else {
|
153
|
+
testModuleMetaData.declarations.push(component);
|
154
|
+
}
|
155
|
+
if (!testModuleMetaData.imports.includes(CommonModule)) {
|
156
|
+
testModuleMetaData.imports.push(CommonModule);
|
157
|
+
}
|
158
|
+
return testModuleMetaData;
|
159
|
+
}
|
160
|
+
let CypressTestComponentRenderer = class CypressTestComponentRenderer extends TestComponentRenderer {
|
161
|
+
insertRootElement(rootElId) {
|
162
|
+
this.removeAllRootElements();
|
163
|
+
const rootElement = getContainerEl();
|
164
|
+
rootElement.setAttribute('id', rootElId);
|
165
|
+
}
|
166
|
+
removeAllRootElements() {
|
167
|
+
getContainerEl().innerHTML = '';
|
168
|
+
}
|
169
|
+
};
|
170
|
+
CypressTestComponentRenderer = __decorate([
|
171
|
+
Injectable()
|
172
|
+
], CypressTestComponentRenderer);
|
173
|
+
/**
|
174
|
+
* Initializes the TestBed
|
175
|
+
*
|
176
|
+
* @param {Type<T> | string} component Angular component being mounted or its template
|
177
|
+
* @param {MountConfig} config TestBed configuration passed into the mount function
|
178
|
+
* @returns {Type<T>} componentFixture
|
179
|
+
*/
|
180
|
+
function initTestBed(component, config) {
|
181
|
+
const componentFixture = createComponentFixture(component);
|
182
|
+
getTestBed().configureTestingModule(Object.assign({}, bootstrapModule(componentFixture, config)));
|
183
|
+
getTestBed().overrideProvider(TestComponentRenderer, { useValue: new CypressTestComponentRenderer() });
|
184
|
+
return componentFixture;
|
185
|
+
}
|
186
|
+
let WrapperComponent = class WrapperComponent {
|
187
|
+
};
|
188
|
+
WrapperComponent = __decorate([
|
189
|
+
Component({ selector: 'cy-wrapper-component', template: '' })
|
190
|
+
], WrapperComponent);
|
191
|
+
/**
|
192
|
+
* Returns the Component if Type<T> or creates a WrapperComponent
|
193
|
+
*
|
194
|
+
* @param {Type<T> | string} component The component you want to create a fixture of
|
195
|
+
* @returns {Type<T> | WrapperComponent}
|
196
|
+
*/
|
197
|
+
function createComponentFixture(component) {
|
198
|
+
if (typeof component === 'string') {
|
199
|
+
// getTestBed().overrideTemplate is available in v14+
|
200
|
+
// The static TestBed.overrideTemplate is available across versions
|
201
|
+
TestBed.overrideTemplate(WrapperComponent, component);
|
202
|
+
return WrapperComponent;
|
203
|
+
}
|
204
|
+
return component;
|
205
|
+
}
|
206
|
+
/**
|
207
|
+
* Creates the ComponentFixture
|
208
|
+
*
|
209
|
+
* @param {Type<T>} component Angular component being mounted
|
210
|
+
* @param {MountConfig<T>} config MountConfig
|
211
|
+
|
212
|
+
* @returns {ComponentFixture<T>} ComponentFixture
|
213
|
+
*/
|
214
|
+
function setupFixture(component, config) {
|
215
|
+
const fixture = getTestBed().createComponent(component);
|
216
|
+
setupComponent(config, fixture);
|
217
|
+
fixture.whenStable().then(() => {
|
218
|
+
var _a;
|
219
|
+
fixture.autoDetectChanges((_a = config.autoDetectChanges) !== null && _a !== void 0 ? _a : true);
|
220
|
+
});
|
221
|
+
return fixture;
|
222
|
+
}
|
223
|
+
/**
|
224
|
+
* Gets the componentInstance and Object.assigns any componentProperties() passed in the MountConfig
|
225
|
+
*
|
226
|
+
* @param {MountConfig} config TestBed configuration passed into the mount function
|
227
|
+
* @param {ComponentFixture<T>} fixture Fixture for debugging and testing a component.
|
228
|
+
* @returns {T} Component being mounted
|
229
|
+
*/
|
230
|
+
function setupComponent(config, fixture) {
|
231
|
+
let component = fixture.componentInstance;
|
232
|
+
if (config === null || config === void 0 ? void 0 : config.componentProperties) {
|
233
|
+
component = Object.assign(component, config.componentProperties);
|
234
|
+
}
|
235
|
+
if (config.autoSpyOutputs) {
|
236
|
+
Object.keys(component).forEach((key) => {
|
237
|
+
const property = component[key];
|
238
|
+
if (property instanceof EventEmitter) {
|
239
|
+
component[key] = createOutputSpy(`${key}Spy`);
|
240
|
+
}
|
241
|
+
});
|
242
|
+
}
|
243
|
+
// Manually call ngOnChanges when mounting components using the class syntax.
|
244
|
+
// This is necessary because we are assigning input values to the class directly
|
245
|
+
// on mount and therefore the ngOnChanges() lifecycle is not triggered.
|
246
|
+
if (component.ngOnChanges && config.componentProperties) {
|
247
|
+
const { componentProperties } = config;
|
248
|
+
const simpleChanges = Object.entries(componentProperties).reduce((acc, [key, value]) => {
|
249
|
+
acc[key] = new SimpleChange(null, value, true);
|
250
|
+
return acc;
|
251
|
+
}, {});
|
252
|
+
if (Object.keys(componentProperties).length > 0) {
|
253
|
+
component.ngOnChanges(simpleChanges);
|
254
|
+
}
|
255
|
+
}
|
256
|
+
}
|
257
|
+
/**
|
258
|
+
* Mounts an Angular component inside Cypress browser
|
259
|
+
*
|
260
|
+
* @param component Angular component being mounted or its template
|
261
|
+
* @param config configuration used to configure the TestBed
|
262
|
+
* @example
|
263
|
+
* import { mount } from '@cypress/angular'
|
264
|
+
* import { StepperComponent } from './stepper.component'
|
265
|
+
* import { MyService } from 'services/my.service'
|
266
|
+
* import { SharedModule } from 'shared/shared.module';
|
267
|
+
* it('mounts', () => {
|
268
|
+
* mount(StepperComponent, {
|
269
|
+
* providers: [MyService],
|
270
|
+
* imports: [SharedModule]
|
271
|
+
* })
|
272
|
+
* cy.get('[data-cy=increment]').click()
|
273
|
+
* cy.get('[data-cy=counter]').should('have.text', '1')
|
274
|
+
* })
|
275
|
+
*
|
276
|
+
* // or
|
277
|
+
*
|
278
|
+
* it('mounts with template', () => {
|
279
|
+
* mount('<app-stepper></app-stepper>', {
|
280
|
+
* declarations: [StepperComponent],
|
281
|
+
* })
|
282
|
+
* })
|
283
|
+
*
|
284
|
+
* @see {@link https://on.cypress.io/mounting-angular} for more details.
|
285
|
+
*
|
286
|
+
* @returns A component and component fixture
|
287
|
+
*/
|
288
|
+
function mount(component, config = {}) {
|
289
|
+
// Remove last mounted component if cy.mount is called more than once in a test
|
290
|
+
if (activeFixture) {
|
291
|
+
cleanup();
|
292
|
+
}
|
293
|
+
const componentFixture = initTestBed(component, config);
|
294
|
+
activeFixture = setupFixture(componentFixture, config);
|
295
|
+
const mountResponse = {
|
296
|
+
fixture: activeFixture,
|
297
|
+
component: activeFixture.componentInstance,
|
298
|
+
};
|
299
|
+
const logMessage = typeof component === 'string' ? 'Component' : componentFixture.name;
|
300
|
+
Cypress.log({
|
301
|
+
name: 'mount',
|
302
|
+
message: logMessage,
|
303
|
+
consoleProps: () => ({ result: mountResponse }),
|
304
|
+
});
|
305
|
+
return cy.wrap(mountResponse, { log: false });
|
306
|
+
}
|
307
|
+
/**
|
308
|
+
* Creates a new Event Emitter and then spies on it's `emit` method
|
309
|
+
*
|
310
|
+
* @param {string} alias name you want to use for your cy.spy() alias
|
311
|
+
* @returns EventEmitter<T>
|
312
|
+
* @example
|
313
|
+
* import { StepperComponent } from './stepper.component'
|
314
|
+
* import { mount, createOutputSpy } from '@cypress/angular'
|
315
|
+
*
|
316
|
+
* it('Has spy', () => {
|
317
|
+
* mount(StepperComponent, { componentProperties: { change: createOutputSpy('changeSpy') } })
|
318
|
+
* cy.get('[data-cy=increment]').click()
|
319
|
+
* cy.get('@changeSpy').should('have.been.called')
|
320
|
+
* })
|
321
|
+
*/
|
322
|
+
const createOutputSpy = (alias) => {
|
323
|
+
const emitter = new EventEmitter();
|
324
|
+
cy.spy(emitter, 'emit').as(alias);
|
325
|
+
return emitter;
|
326
|
+
};
|
327
|
+
// Only needs to run once, we reset before each test
|
328
|
+
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), {
|
329
|
+
teardown: { destroyAfterEach: false },
|
330
|
+
});
|
331
|
+
setupHooks(cleanup);
|
332
|
+
|
333
|
+
export { CypressTestComponentRenderer, createOutputSpy, mount };
|
@@ -0,0 +1,77 @@
|
|
1
|
+
{
|
2
|
+
"name": "@cypress/angular",
|
3
|
+
"version": "0.0.0-development",
|
4
|
+
"description": "Test Angular Components using Cypress",
|
5
|
+
"main": "dist/index.js",
|
6
|
+
"scripts": {
|
7
|
+
"prebuild": "rimraf dist",
|
8
|
+
"build": "rollup -c rollup.config.mjs",
|
9
|
+
"postbuild": "node ../../scripts/sync-exported-npm-with-cli.js",
|
10
|
+
"check-ts": "tsc --noEmit",
|
11
|
+
"lint": "eslint --ext .js,.ts,.json, ."
|
12
|
+
},
|
13
|
+
"dependencies": {},
|
14
|
+
"devDependencies": {
|
15
|
+
"@angular/common": "^14.2.0",
|
16
|
+
"@angular/core": "^14.2.0",
|
17
|
+
"@angular/platform-browser-dynamic": "^14.2.0",
|
18
|
+
"@cypress/mount-utils": "0.0.0-development",
|
19
|
+
"typescript": "^4.7.4",
|
20
|
+
"zone.js": "~0.11.4"
|
21
|
+
},
|
22
|
+
"peerDependencies": {
|
23
|
+
"@angular/common": ">=13",
|
24
|
+
"@angular/core": ">=13",
|
25
|
+
"@angular/platform-browser-dynamic": ">=13",
|
26
|
+
"zone.js": ">=0.11.0"
|
27
|
+
},
|
28
|
+
"files": [
|
29
|
+
"dist"
|
30
|
+
],
|
31
|
+
"types": "dist/index.d.ts",
|
32
|
+
"license": "MIT",
|
33
|
+
"repository": {
|
34
|
+
"type": "git",
|
35
|
+
"url": "https://github.com/cypress-io/cypress.git"
|
36
|
+
},
|
37
|
+
"homepage": "https://github.com/cypress-io/cypress/blob/develop/npm/angular/#readme",
|
38
|
+
"author": "Jordan Powell",
|
39
|
+
"bugs": "https://github.com/cypress-io/cypress/issues/new?assignees=&labels=npm%3A%20%40cypress%2Fangular&template=1-bug-report.md&title=",
|
40
|
+
"keywords": [
|
41
|
+
"angular",
|
42
|
+
"cypress",
|
43
|
+
"cypress-io",
|
44
|
+
"test",
|
45
|
+
"testing"
|
46
|
+
],
|
47
|
+
"contributors": [
|
48
|
+
{
|
49
|
+
"name": "Jordan Powell",
|
50
|
+
"social": "@jordanpowell88"
|
51
|
+
},
|
52
|
+
{
|
53
|
+
"name": "Zach Williams",
|
54
|
+
"social": "@ZachJW34"
|
55
|
+
}
|
56
|
+
],
|
57
|
+
"module": "dist/index.js",
|
58
|
+
"publishConfig": {
|
59
|
+
"access": "public"
|
60
|
+
},
|
61
|
+
"nx": {
|
62
|
+
"targets": {
|
63
|
+
"build": {
|
64
|
+
"outputs": [
|
65
|
+
"{workspaceRoot}/cli/angular"
|
66
|
+
]
|
67
|
+
}
|
68
|
+
}
|
69
|
+
},
|
70
|
+
"standard": {
|
71
|
+
"globals": [
|
72
|
+
"Cypress",
|
73
|
+
"cy",
|
74
|
+
"expect"
|
75
|
+
]
|
76
|
+
}
|
77
|
+
}
|
package/angular/package.json
CHANGED
@@ -7,7 +7,6 @@
|
|
7
7
|
"prebuild": "rimraf dist",
|
8
8
|
"build": "rollup -c rollup.config.mjs",
|
9
9
|
"postbuild": "node ../../scripts/sync-exported-npm-with-cli.js",
|
10
|
-
"build-prod": "yarn build",
|
11
10
|
"check-ts": "tsc --noEmit",
|
12
11
|
"lint": "eslint --ext .js,.ts,.json, ."
|
13
12
|
},
|
@@ -59,6 +58,15 @@
|
|
59
58
|
"publishConfig": {
|
60
59
|
"access": "public"
|
61
60
|
},
|
61
|
+
"nx": {
|
62
|
+
"targets": {
|
63
|
+
"build": {
|
64
|
+
"outputs": [
|
65
|
+
"{workspaceRoot}/cli/angular"
|
66
|
+
]
|
67
|
+
}
|
68
|
+
}
|
69
|
+
},
|
62
70
|
"standard": {
|
63
71
|
"globals": [
|
64
72
|
"Cypress",
|
package/lib/exec/spawn.js
CHANGED
package/lib/util.js
CHANGED
@@ -251,7 +251,7 @@ const util = {
|
|
251
251
|
return tty.isatty(fd);
|
252
252
|
},
|
253
253
|
supportsColor() {
|
254
|
-
// if we've been
|
254
|
+
// if we've been explicitly told not to support
|
255
255
|
// color then turn this off
|
256
256
|
if (process.env.NO_COLOR) {
|
257
257
|
return false;
|