mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
test(devtools): revive cypress tests (#61972)
Previously these tests would run automatically when Angular DevTools lived in another repo. These files have continued to live here but have not been running automatically on each PR. Now, these test files have been revived to run properly with our changes since the repo merge. This is a first step to reviving our e2e testing. Next steps include writing cypress tests for new features like Injector Graph, Router tree, signals visualizations, etc. PR Close #61972
This commit is contained in:
parent
c4dd258658
commit
75d246e03c
18 changed files with 179 additions and 148 deletions
9
.github/workflows/ci.yml
vendored
9
.github/workflows/ci.yml
vendored
|
|
@ -56,6 +56,15 @@ jobs:
|
|||
run: yarn devtools:test
|
||||
- name: Test build
|
||||
run: yarn devtools:build:chrome
|
||||
- name: Install Cypress
|
||||
run: yarn global add cypress@14.4.1
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@6c143abc292aa835d827652c2ea025d098311070 # v6.10.1
|
||||
with:
|
||||
command: cypress run --project ./devtools/cypress
|
||||
start: yarn bazel run //devtools/src:devserver
|
||||
wait-on: 'http://localhost:4200'
|
||||
wait-on-timeout: 300
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest-4core
|
||||
|
|
|
|||
9
.github/workflows/pr.yml
vendored
9
.github/workflows/pr.yml
vendored
|
|
@ -60,6 +60,15 @@ jobs:
|
|||
run: yarn devtools:test
|
||||
- name: Test build
|
||||
run: yarn devtools:build:chrome
|
||||
- name: Install Cypress
|
||||
run: yarn global add cypress@14.4.1
|
||||
- name: Cypress run
|
||||
uses: cypress-io/github-action@6c143abc292aa835d827652c2ea025d098311070 # v6.10.1
|
||||
with:
|
||||
command: cypress run --project ./devtools/cypress
|
||||
start: yarn bazel run //devtools/src:devserver
|
||||
wait-on: 'http://localhost:4200'
|
||||
wait-on-timeout: 300
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest-8core
|
||||
|
|
|
|||
15
devtools/cypress/cypress.config.js
Normal file
15
devtools/cypress/cypress.config.js
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
/**
|
||||
* @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.dev/license
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
e2e: {
|
||||
specPattern: 'integration/*.e2e.js',
|
||||
supportFile: 'support/index.js',
|
||||
baseUrl: 'http://localhost:4200',
|
||||
},
|
||||
};
|
||||
|
|
@ -6,15 +6,13 @@
|
|||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
require('cypress-iframe');
|
||||
|
||||
describe('Testing the Todo app Demo', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/');
|
||||
});
|
||||
|
||||
it('should contain the todos application', () => {
|
||||
cy.enter('#sample-app').then((getBody) => {
|
||||
cy.enterIframe('#sample-app').then((getBody) => {
|
||||
getBody().contains('Todos');
|
||||
getBody().contains('About');
|
||||
getBody().contains('Clear completed');
|
||||
|
|
@ -23,15 +21,15 @@ describe('Testing the Todo app Demo', () => {
|
|||
});
|
||||
|
||||
it('should contain the "Components" tab', () => {
|
||||
cy.contains('.mat-tab-links', 'Components');
|
||||
cy.contains('.devtools-nav', 'Components');
|
||||
});
|
||||
|
||||
it('should contain the "Profiler" tab', () => {
|
||||
cy.contains('.mat-tab-links', 'Profiler');
|
||||
cy.contains('.devtools-nav', 'Profiler');
|
||||
});
|
||||
|
||||
it('should contain "app-root" and "app-todo-demo" in the component tree', () => {
|
||||
cy.contains('.tree-node', 'app-root');
|
||||
cy.contains('.tree-node', 'app-todo-demo');
|
||||
cy.contains('ng-tree-node', 'app-root');
|
||||
cy.contains('ng-tree-node', 'app-todo-demo');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
function showComments() {
|
||||
cy.get('#nav-buttons > button:nth-child(2)').click();
|
||||
cy.get('#mat-slide-toggle-3 > label > div').click();
|
||||
cy.get('.cdk-overlay-container mat-slide-toggle label:contains("Show comment nodes")').click();
|
||||
}
|
||||
|
||||
describe('Comment nodes', () => {
|
||||
|
|
@ -17,14 +17,14 @@ describe('Comment nodes', () => {
|
|||
});
|
||||
|
||||
it('should not find any comment nodes by default', () => {
|
||||
const nodes = cy.$$('.tree-node:contains("#comment")');
|
||||
const nodes = cy.$$('ng-tree-node:contains("#comment")');
|
||||
expect(nodes.length).to.eql(0);
|
||||
});
|
||||
|
||||
it('should find comment nodes when the setting is enabled', () => {
|
||||
showComments();
|
||||
cy.get('.tree-wrapper')
|
||||
.find('.tree-node:contains("#comment")')
|
||||
.find('ng-tree-node:contains("#comment")')
|
||||
.its('length')
|
||||
.should('not.eq', 0);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ describe('Angular Elements', () => {
|
|||
});
|
||||
|
||||
it('should recognize the zippy as an Angular Element', () => {
|
||||
cy.get('.tree-wrapper').find('.tree-node:contains("app-zippy")').its('length').should('eq', 1);
|
||||
cy.get('.tree-wrapper')
|
||||
.find('ng-tree-node:contains("app-zippy")')
|
||||
.its('length')
|
||||
.should('eq', 1);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,31 +6,29 @@
|
|||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
require('cypress-iframe');
|
||||
|
||||
describe('Tracking items from application to component tree', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/');
|
||||
});
|
||||
|
||||
it('should have only one todo item on start', () => {
|
||||
cy.enter('#sample-app').then((getBody) => {
|
||||
cy.enterIframe('#sample-app').then((getBody) => {
|
||||
getBody().find('app-todo').contains('Buy milk');
|
||||
});
|
||||
|
||||
cy.get('.tree-wrapper')
|
||||
.find('.tree-node:contains("app-todo[TooltipDirective]")')
|
||||
.find('ng-tree-node:contains("app-todo[TooltipDirective]")')
|
||||
.its('length')
|
||||
.should('eq', 2);
|
||||
});
|
||||
|
||||
it('should be able to detect a new todo from user and add it to the tree', () => {
|
||||
cy.enter('#sample-app')
|
||||
cy.enterIframe('#sample-app')
|
||||
.then((getBody) => {
|
||||
getBody().find('input.new-todo').type('Buy cookies{enter}');
|
||||
})
|
||||
.then(() => {
|
||||
cy.enter('#sample-app').then((getBody) => {
|
||||
cy.enterIframe('#sample-app').then((getBody) => {
|
||||
getBody().find('app-todo').contains('Buy milk');
|
||||
|
||||
getBody().find('app-todo').contains('Build something fun!');
|
||||
|
|
@ -39,7 +37,7 @@ describe('Tracking items from application to component tree', () => {
|
|||
});
|
||||
});
|
||||
|
||||
cy.get('.tree-wrapper .tree-node:contains("app-todo[TooltipDirective]")').should(
|
||||
cy.get('.tree-wrapper ng-tree-node:contains("app-todo[TooltipDirective]")').should(
|
||||
'have.length',
|
||||
3,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ function checkSearchedNodesLength(type, length) {
|
|||
}
|
||||
|
||||
function inputSearchText(text) {
|
||||
cy.get('.filter-input').type(text, {force: true});
|
||||
cy.get('ng-filter .filter-input').type(text, {force: true});
|
||||
}
|
||||
|
||||
function checkComponentName(name) {
|
||||
|
|
@ -19,7 +19,7 @@ function checkComponentName(name) {
|
|||
}
|
||||
|
||||
function checkEmptyNodes() {
|
||||
cy.get('.tree-wrapper').find('.matched').should('not.exist');
|
||||
cy.get('.tree-wrapper').find('.matched-text').should('not.exist');
|
||||
}
|
||||
|
||||
function clickSearchArrows(upwards) {
|
||||
|
|
@ -44,7 +44,7 @@ describe('Search items in component tree', () => {
|
|||
|
||||
it('should highlight correct nodes when searching and clear out', () => {
|
||||
inputSearchText('todo');
|
||||
checkSearchedNodesLength('.matched', 4);
|
||||
checkSearchedNodesLength('.matched-text', 4);
|
||||
|
||||
// clear search input
|
||||
inputSearchText('{backspace}{backspace}{backspace}{backspace}');
|
||||
|
|
@ -53,22 +53,23 @@ describe('Search items in component tree', () => {
|
|||
|
||||
it('should highlight correct nodes when searching and using arrow keys', () => {
|
||||
inputSearchText('todo');
|
||||
checkSearchedNodesLength('.matched', 4);
|
||||
checkSearchedNodesLength('.matched-text', 4);
|
||||
checkComponentName('app-todo-demo');
|
||||
|
||||
// press down arrow
|
||||
clickSearchArrows(false);
|
||||
checkSearchedNodesLength('.selected', 1);
|
||||
checkComponentName('app-todo-demo');
|
||||
checkComponentName('app-todos');
|
||||
|
||||
// press up arrow
|
||||
// press down arrow
|
||||
clickSearchArrows(false);
|
||||
checkSearchedNodesLength('.selected', 1);
|
||||
checkComponentName('app-todos');
|
||||
checkComponentName('app-todo');
|
||||
|
||||
// press up arrow
|
||||
clickSearchArrows(true);
|
||||
checkSearchedNodesLength('.selected', 1);
|
||||
checkComponentName('app-todo-demo');
|
||||
checkComponentName('app-todos');
|
||||
|
||||
// clear search input
|
||||
inputSearchText('{backspace}{backspace}{backspace}{backspace}');
|
||||
|
|
@ -76,7 +77,7 @@ describe('Search items in component tree', () => {
|
|||
});
|
||||
|
||||
it('should select correct node on enter', () => {
|
||||
inputSearchText('todos{enter}');
|
||||
inputSearchText('todo{enter}');
|
||||
checkSearchedNodesLength('.selected', 1);
|
||||
|
||||
// should show correct buttons in breadcrumbs
|
||||
|
|
@ -91,7 +92,7 @@ describe('Search items in component tree', () => {
|
|||
checkComponentName('app-todos');
|
||||
|
||||
// should display correct title for properties panel
|
||||
cy.get('ng-property-view-header').should('have.text', 'app-todos');
|
||||
cy.get('ng-property-view-header').should('contain.text', 'app-todos');
|
||||
|
||||
// should show correct component properties
|
||||
cy.get('ng-property-view').find('mat-tree-node');
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@
|
|||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
require('cypress-iframe');
|
||||
|
||||
describe('node selection', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/');
|
||||
|
|
@ -15,49 +13,55 @@ describe('node selection', () => {
|
|||
|
||||
describe('logic after change detection', () => {
|
||||
it('should deselect node if it is no longer on the page', () => {
|
||||
cy.get('.tree-wrapper').get('.tree-node.selected').should('not.exist');
|
||||
cy.get('.tree-wrapper')
|
||||
.get('ng-tree-node:contains("app-todo[TooltipDirective]")')
|
||||
.should('not.have.class', 'selected');
|
||||
|
||||
cy.get('.tree-wrapper')
|
||||
.find('.tree-node:contains("app-todo[TooltipDirective]")')
|
||||
.find('ng-tree-node:contains("app-todo[TooltipDirective]")')
|
||||
.first()
|
||||
.click({force: true});
|
||||
|
||||
cy.get('.tree-wrapper').find('.tree-node.selected').its('length').should('eq', 1);
|
||||
cy.get('.tree-wrapper')
|
||||
.get('ng-tree-node:contains("app-todo[TooltipDirective]")')
|
||||
.should('have.class', 'selected');
|
||||
|
||||
cy.enter('#sample-app').then((getBody) => {
|
||||
cy.enterIframe('#sample-app').then((getBody) => {
|
||||
getBody().find('a:contains("About")').click();
|
||||
});
|
||||
|
||||
cy.get('.tree-wrapper').get('.tree-node.selected').should('not.exist');
|
||||
cy.get('.tree-wrapper')
|
||||
.get('ng-tree-node:contains("app-todo[TooltipDirective]")')
|
||||
.should('not.exist');
|
||||
});
|
||||
|
||||
it('should reselect the previously selected node if it is still present', () => {
|
||||
cy.get('.tree-wrapper').get('.tree-node.selected').should('not.exist');
|
||||
cy.get('.tree-wrapper').get('ng-tree-node.selected').should('not.exist');
|
||||
|
||||
cy.enter('#sample-app').then((getBody) => {
|
||||
cy.enterIframe('#sample-app').then((getBody) => {
|
||||
getBody().find('input.new-todo').type('Buy cookies{enter}');
|
||||
});
|
||||
|
||||
cy.get('.tree-wrapper')
|
||||
.find('.tree-node:contains("app-todo[TooltipDirective]")')
|
||||
.find('ng-tree-node:contains("app-todo[TooltipDirective]")')
|
||||
.last()
|
||||
.click({force: true});
|
||||
|
||||
cy.enter('#sample-app').then((getBody) => {
|
||||
cy.enterIframe('#sample-app').then((getBody) => {
|
||||
getBody().find('app-todo:contains("Buy milk")').find('.destroy').click();
|
||||
});
|
||||
|
||||
cy.get('.tree-wrapper').find('.tree-node.selected').its('length').should('eq', 1);
|
||||
cy.get('.tree-wrapper').find('ng-tree-node.selected').its('length').should('eq', 1);
|
||||
});
|
||||
|
||||
it('should select nodes with same name', () => {
|
||||
cy.get('.tree-wrapper')
|
||||
.find('.tree-node:contains("app-todo[TooltipDirective]")')
|
||||
.find('ng-tree-node:contains("app-todo[TooltipDirective]")')
|
||||
.first()
|
||||
.click({force: true});
|
||||
|
||||
cy.get('.tree-wrapper')
|
||||
.find('.tree-node:contains("app-todo[TooltipDirective]")')
|
||||
.find('ng-tree-node:contains("app-todo[TooltipDirective]")')
|
||||
.last()
|
||||
.click({force: true});
|
||||
|
||||
|
|
@ -74,7 +78,7 @@ describe('node selection', () => {
|
|||
describe('breadcrumb logic', () => {
|
||||
it('should overflow when breadcrumb list is long enough', () => {
|
||||
cy.get('.tree-wrapper')
|
||||
.find('.tree-node:contains("div[TooltipDirective]")')
|
||||
.find('ng-tree-node:contains("div[TooltipDirective]")')
|
||||
.last()
|
||||
.click({force: true})
|
||||
.then(() => {
|
||||
|
|
@ -90,7 +94,7 @@ describe('node selection', () => {
|
|||
|
||||
it('should scroll right when right scroll button is clicked', () => {
|
||||
cy.get('.tree-wrapper')
|
||||
.find('.tree-node:contains("div[TooltipDirective]")')
|
||||
.find('ng-tree-node:contains("div[TooltipDirective]")')
|
||||
.last()
|
||||
.click({force: true})
|
||||
.then(() => {
|
||||
|
|
@ -106,7 +110,7 @@ describe('node selection', () => {
|
|||
cy.get('ng-breadcrumbs')
|
||||
.find('.scroll-button')
|
||||
.last()
|
||||
.click()
|
||||
.click({force: true})
|
||||
.then(() => {
|
||||
expect(scrollLeft()).to.be.greaterThan(0);
|
||||
});
|
||||
|
|
@ -116,7 +120,7 @@ describe('node selection', () => {
|
|||
|
||||
it('should scroll left when left scroll button is clicked', () => {
|
||||
cy.get('.tree-wrapper')
|
||||
.find('.tree-node:contains("div[TooltipDirective]")')
|
||||
.find('ng-tree-node:contains("div[TooltipDirective]")')
|
||||
.last()
|
||||
.click({force: true})
|
||||
.then(() => {
|
||||
|
|
@ -132,14 +136,14 @@ describe('node selection', () => {
|
|||
cy.get('ng-breadcrumbs')
|
||||
.find('.scroll-button')
|
||||
.last()
|
||||
.click()
|
||||
.click({force: true})
|
||||
.then(() => {
|
||||
expect(scrollLeft()).to.be.greaterThan(0);
|
||||
|
||||
cy.get('ng-breadcrumbs')
|
||||
.find('.scroll-button')
|
||||
.first()
|
||||
.click()
|
||||
.click({force: true})
|
||||
.then(() => {
|
||||
expect(scrollLeft()).to.eql(0);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@
|
|||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
require('cypress-iframe');
|
||||
|
||||
describe('edit properties of directive in the property view tab', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/');
|
||||
|
|
@ -17,13 +15,13 @@ describe('edit properties of directive in the property view tab', () => {
|
|||
beforeEach(() => {
|
||||
// select todo node in component tree
|
||||
cy.get('.tree-wrapper')
|
||||
.find('.tree-node:contains("app-todo[TooltipDirective]")')
|
||||
.find('ng-tree-node:contains("app-todo[TooltipDirective]")')
|
||||
.first()
|
||||
.click({force: true});
|
||||
});
|
||||
|
||||
it('should be able to enable editMode', () => {
|
||||
cy.enter('#sample-app').then((getBody) => {
|
||||
cy.enterIframe('#sample-app').then((getBody) => {
|
||||
getBody().find('app-todo input.edit').should('not.be.visible');
|
||||
});
|
||||
|
||||
|
|
@ -36,61 +34,38 @@ describe('edit properties of directive in the property view tab', () => {
|
|||
.type('true')
|
||||
.type('{enter}');
|
||||
|
||||
cy.enter('#sample-app').then((getBody) => {
|
||||
cy.enterIframe('#sample-app').then((getBody) => {
|
||||
getBody().find('app-todo input.edit').should('be.visible');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('edit todo property', () => {
|
||||
beforeEach(() => {
|
||||
// expand todo state
|
||||
cy.get('.explorer-panel:contains("app-todo")')
|
||||
.find('ng-property-view mat-tree-node:contains("todo")')
|
||||
.click();
|
||||
describe('edit title property', () => {
|
||||
beforeEach(() => {
|
||||
cy.get('.tree-wrapper')
|
||||
.find('ng-tree-node:contains("app-todos")')
|
||||
.first()
|
||||
.click({force: true});
|
||||
});
|
||||
|
||||
it('should change title in app when edited', () => {
|
||||
cy.enterIframe('#sample-app').then((getBody) => {
|
||||
getBody().find('#demo-app-title').contains('Angular Todo');
|
||||
});
|
||||
|
||||
it('should change todo label in app when edited', () => {
|
||||
// check initial todo label
|
||||
cy.enter('#sample-app').then((getBody) => {
|
||||
getBody().find('app-todo').contains('Buy milk').its('length').should('eq', 1);
|
||||
});
|
||||
// find title variable and run through edit logic
|
||||
cy.get('.explorer-panel:contains("app-todos")')
|
||||
.find('ng-property-view mat-tree-node:contains("title")')
|
||||
.find('ng-property-editor .editor')
|
||||
.click()
|
||||
.find('.editor-input')
|
||||
.clear()
|
||||
.type('Hello World')
|
||||
.type('{enter}');
|
||||
|
||||
// find label variable and run through edit logic
|
||||
cy.get('.explorer-panel:contains("app-todo")')
|
||||
.find('ng-property-view mat-tree-node:contains("label")')
|
||||
.find('ng-property-editor .editor')
|
||||
.click()
|
||||
.find('.editor-input')
|
||||
.clear()
|
||||
.type('Buy cookies')
|
||||
.type('{enter}');
|
||||
|
||||
// assert that the page has been updated
|
||||
cy.enter('#sample-app').then((getBody) => {
|
||||
getBody().find('app-todo').contains('Buy cookies').its('length').should('eq', 1);
|
||||
});
|
||||
});
|
||||
|
||||
it('should change todo completed in app when edited', () => {
|
||||
// check initial todo completed status
|
||||
cy.enter('#sample-app').then((getBody) => {
|
||||
getBody().find('app-todo li').not('.completed').its('length').should('eq', 2);
|
||||
});
|
||||
|
||||
// find completed variable and run through edit logic
|
||||
cy.get('.explorer-panel:contains("app-todo")')
|
||||
.find('ng-property-view mat-tree-node:contains("completed")')
|
||||
.find('ng-property-editor .editor')
|
||||
.click()
|
||||
.find('.editor-input')
|
||||
.clear()
|
||||
.type('true')
|
||||
.type('{enter}');
|
||||
|
||||
// assert that the page has been updated
|
||||
cy.enter('#sample-app').then((getBody) => {
|
||||
getBody().find('app-todo li.completed').its('length').should('eq', 1);
|
||||
});
|
||||
// assert that the page has been updated
|
||||
cy.enterIframe('#sample-app').then((getBody) => {
|
||||
getBody().find('#demo-app-title').contains('Hello World');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@
|
|||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
require('cypress-iframe');
|
||||
|
||||
describe('change of the state should reflect in property update', () => {
|
||||
beforeEach(() => {
|
||||
cy.visit('/');
|
||||
|
|
@ -15,13 +13,13 @@ describe('change of the state should reflect in property update', () => {
|
|||
|
||||
it('should update the property value', () => {
|
||||
// Complete the todo
|
||||
cy.enter('#sample-app').then((getBody) => {
|
||||
cy.enterIframe('#sample-app').then((getBody) => {
|
||||
getBody().find('input[type="checkbox"].toggle').first().click();
|
||||
});
|
||||
|
||||
// Select the todo item
|
||||
cy.get('.tree-wrapper')
|
||||
.find('.tree-node:contains("app-todo[TooltipDirective]")')
|
||||
.find('ng-tree-node:contains("app-todo[TooltipDirective]")')
|
||||
.first()
|
||||
.click({force: true});
|
||||
|
||||
|
|
|
|||
|
|
@ -16,49 +16,49 @@ describe('Viewing component metadata', () => {
|
|||
cy.visit('/');
|
||||
});
|
||||
|
||||
describe('viewing TodoComponent', () => {
|
||||
describe('viewing TodosComponent', () => {
|
||||
beforeEach(() =>
|
||||
prepareHeaderExpansionPanelForAssertions('.tree-node:contains("app-todo[TooltipDirective]")'),
|
||||
prepareHeaderExpansionPanelForAssertions('ng-tree-node:contains("app-todos")'),
|
||||
);
|
||||
|
||||
it('should display view encapsulation', () => {
|
||||
cy.contains('.meta-data-container .mat-button:first', 'View Encapsulation: Emulated');
|
||||
cy.contains('.meta-data-container', 'View Encapsulation: None');
|
||||
});
|
||||
|
||||
it('should display change detection strategy', () => {
|
||||
cy.contains('.meta-data-container .mat-button:last', 'Change Detection Strategy: OnPush');
|
||||
cy.contains('.meta-data-container', 'Change Detection Strategy: Default');
|
||||
});
|
||||
});
|
||||
|
||||
describe('viewing DemoAppComponent', () => {
|
||||
beforeEach(() =>
|
||||
prepareHeaderExpansionPanelForAssertions('.tree-node:contains("app-demo-component")'),
|
||||
prepareHeaderExpansionPanelForAssertions('ng-tree-node:contains("app-demo-component")'),
|
||||
);
|
||||
|
||||
it('should display view encapsulation', () => {
|
||||
cy.contains('.meta-data-container .mat-button:first', 'View Encapsulation: None');
|
||||
cy.contains('.meta-data-container', 'View Encapsulation: None');
|
||||
});
|
||||
|
||||
it('should display change detection strategy', () => {
|
||||
cy.contains('.meta-data-container .mat-button:last', 'Change Detection Strategy: Default');
|
||||
cy.contains('.meta-data-container', 'Change Detection Strategy: Default');
|
||||
});
|
||||
|
||||
it('should display correct set of inputs', () => {
|
||||
cy.contains('.cy-inputs', 'Inputs');
|
||||
cy.contains('.cy-inputs mat-tree-node:first span:first', 'inputOne');
|
||||
cy.contains('.cy-inputs mat-tree-node:last span:first', 'inputTwo');
|
||||
cy.contains('.mat-accordion-content#Inputs', 'Inputs');
|
||||
cy.contains('.mat-accordion-content#Inputs mat-tree-node:first span:first', 'inputOne');
|
||||
cy.contains('.mat-accordion-content#Inputs mat-tree-node:last span:first', 'inputTwo');
|
||||
});
|
||||
|
||||
it('should display correct set of outputs', () => {
|
||||
cy.contains('.cy-outputs', 'Outputs');
|
||||
cy.contains('.cy-outputs mat-tree-node:first span:first', 'outputOne');
|
||||
cy.contains('.cy-outputs mat-tree-node:last span:first', 'outputTwo');
|
||||
cy.contains('.mat-accordion-content#Outputs', 'Outputs');
|
||||
cy.contains('.mat-accordion-content#Outputs mat-tree-node:first span:first', 'outputOne');
|
||||
cy.contains('.mat-accordion-content#Outputs mat-tree-node:last span:first', 'outputTwo');
|
||||
});
|
||||
|
||||
it('should display correct set of properties', () => {
|
||||
cy.contains('.cy-properties', 'Properties');
|
||||
cy.contains('.cy-properties mat-tree-node:first span:first', 'elementRef');
|
||||
cy.contains('.cy-properties mat-tree-node:last span:first', 'zippy');
|
||||
cy.contains('.mat-accordion-content#Properties', 'Properties');
|
||||
cy.contains('.mat-accordion-content#Properties mat-tree-node:first span:first', 'elementRef');
|
||||
cy.contains('.mat-accordion-content#Properties mat-tree-node:last span:first', 'zippy');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,28 +6,25 @@
|
|||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
// ***********************************************
|
||||
// This example commands.js shows you how to
|
||||
// create various custom commands and overwrite
|
||||
// existing commands.
|
||||
//
|
||||
// For more comprehensive examples of custom
|
||||
// commands please read more here:
|
||||
// https://on.cypress.io/custom-commands
|
||||
// ***********************************************
|
||||
//
|
||||
//
|
||||
// -- This is a parent command --
|
||||
// Cypress.Commands.add("login", (email, password) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
|
||||
/**
|
||||
* Selects an Iframe and returns its body when it's done loading.
|
||||
* @param {string} selector - The selector for the iframe.
|
||||
* @returns {Function} A function that returns the wrapped body of the iframe.
|
||||
*/
|
||||
function enterIframe(selector) {
|
||||
return cy.get(selector, {log: false}).then({timeout: 30000}, async (frame) => {
|
||||
const contentWindow = frame.prop('contentWindow');
|
||||
|
||||
while (
|
||||
contentWindow.location.toString() === 'about:blank' ||
|
||||
contentWindow.document.readyState !== 'complete'
|
||||
) {
|
||||
await new Promise((resolve) => setTimeout(resolve));
|
||||
}
|
||||
|
||||
// return the body of the iframe wrapped in cypress
|
||||
return () => cy.wrap(contentWindow.document.body);
|
||||
});
|
||||
}
|
||||
|
||||
Cypress.Commands.add('enterIframe', enterIframe);
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
</div>
|
||||
}
|
||||
@for (panel of panels(); track $index) {
|
||||
<div class="mat-accordion-content" cdkDrag>
|
||||
<div class="mat-accordion-content" [id]="panel.title()" cdkDrag>
|
||||
@if (panel.controls().dataSource.data.length > 0) {
|
||||
<mat-expansion-panel [expanded]="true">
|
||||
<mat-expansion-panel-header collapsedHeight="28px" expandedHeight="28px">
|
||||
|
|
|
|||
|
|
@ -2,4 +2,5 @@
|
|||
<app-zippy [title]="getTitle()">This is my content</app-zippy>
|
||||
<app-heavy></app-heavy>
|
||||
<div #elementReference>HTMLElement</div>
|
||||
<div *appStructural>Test Structural Directive</div>
|
||||
<app-sample-properties></app-sample-properties>
|
||||
|
|
|
|||
|
|
@ -10,11 +10,15 @@ import {
|
|||
Component,
|
||||
computed,
|
||||
CUSTOM_ELEMENTS_SCHEMA,
|
||||
Directive,
|
||||
ElementRef,
|
||||
inject,
|
||||
input,
|
||||
output,
|
||||
signal,
|
||||
TemplateRef,
|
||||
viewChild,
|
||||
ViewContainerRef,
|
||||
ViewEncapsulation,
|
||||
} from '@angular/core';
|
||||
|
||||
|
|
@ -23,13 +27,30 @@ import {HeavyComponent} from './heavy.component';
|
|||
import {SamplePropertiesComponent} from './sample-properties.component';
|
||||
import {RouterOutlet} from '@angular/router';
|
||||
|
||||
// structual directive example
|
||||
@Directive({
|
||||
selector: '[appStructural]',
|
||||
host: {
|
||||
'[class.app-structural]': 'true',
|
||||
},
|
||||
})
|
||||
export class StructuralDirective {
|
||||
templateRef = inject(TemplateRef);
|
||||
viewContainerRef = inject(ViewContainerRef);
|
||||
|
||||
ngOnInit() {
|
||||
// Example of using the structural directive
|
||||
this.viewContainerRef.createEmbeddedView(this.templateRef);
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-demo-component',
|
||||
templateUrl: './demo-app.component.html',
|
||||
styleUrls: ['./demo-app.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
imports: [HeavyComponent, SamplePropertiesComponent, RouterOutlet],
|
||||
imports: [StructuralDirective, HeavyComponent, SamplePropertiesComponent, RouterOutlet],
|
||||
})
|
||||
export class DemoAppComponent {
|
||||
readonly zippy = viewChild(ZippyComponent);
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<p>{{ 'Sample text processed by a pipe' | sample }}</p>
|
||||
<section class="todoapp">
|
||||
<header class="header">
|
||||
<h1>todos</h1>
|
||||
<h1 id="demo-app-title">{{title}}</h1>
|
||||
<input
|
||||
(keydown.enter)="addTodo(input)"
|
||||
#input
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ const fib = (n: number): number => {
|
|||
imports: [RouterLink, TodoComponent, TooltipDirective, SamplePipe, TodosFilter],
|
||||
})
|
||||
export class TodosComponent implements OnInit, OnDestroy {
|
||||
title = 'Angular Todo';
|
||||
|
||||
todos: Todo[] = [
|
||||
{
|
||||
label: 'Buy milk',
|
||||
|
|
|
|||
Loading…
Reference in a new issue