Отправка MouseEvents, кажется, единственный способ проверить перетаскивание Angular Material.
Вам также следует знать о следующей проблеме, которая тестирует в Protractor, но также относится и к этому тесту Cypress
CDK DragDrop Регрессия между 7.0.0-beta.2 и 7.0.0-rc.2: тесты транспортира перестали работать # 13642 ,
Похоже, что (из-за отсутствия лучшего объяснения) требуется дополнительное толчок мышью.
Шаги, заданные как обходной путь (синтаксис транспортира),
private async dragAndDrop ( $element, $destination ) {
await browser.actions().mouseMove( $element ).perform();
await browser.actions().mouseDown( $element ).perform();
await browser.actions().mouseMove( {x: 10, y: 0 } ).perform();
await browser.actions().mouseMove( $destination ).perform();
return browser.actions().mouseUp().perform();
}
можно перевести в тест Cypress, самая простая форма, которую я нашел, это
it('works (simply)', () => {
const draggable = Cypress.$('#cdk-drop-list-0 > :nth-child(1)')[0] // Pick up this
const droppable = Cypress.$('#cdk-drop-list-1 > :nth-child(4)')[0] // Drop over this
const coords = droppable.getBoundingClientRect()
draggable.dispatchEvent(new MouseEvent('mousedown'));
draggable.dispatchEvent(new MouseEvent('mousemove', {clientX: 10, clientY: 0}));
draggable.dispatchEvent(new MouseEvent('mousemove', {
clientX: coords.x+10,
clientY: coords.y+10 // A few extra pixels to get the ordering right
}));
draggable.dispatchEvent(new MouseEvent('mouseup'));
cy.get('#cdk-drop-list-1').should('contain', 'Get to work');
cy.get('#cdk-drop-list-1 > .cdk-drag').eq(3).should('contain', 'Get to work');
});
Примечания
- Проблема в упомянутой проблеме не ограничивается Транспортиром. Если вы удалите первый
mousemove
в тесте Cypress, он также не будет выполнен.
- Синтаксис
cy.get(..).trigger()
, похоже, не работает с Angular, но собственный dispatchEvent()
работает.
- Перетаскивание определенного элемента в списке целей (в отличие от простого падения в списке) дает точное позиционирование в списке целей.
dragstart, dragend
может не подходить для Angular Material, поскольку код показывает, что полученное событие имеет тип CdkDragDrop
, а не объект DataTransfer.
- Если контент извлекается асинхронно, вам, возможно, придется переключиться с
Cypress.$(...)
на cy.get(...).then(el => {...})
, чтобы воспользоваться преимуществами автоматического повтора команды cypress.
- Мне пришлось добавить 10-секундный тайм-аут, чтобы посетить URL Stackblitz.
Асинхронный выбор списка
Если список выбирается асинхронной угловой службой (httpClient) во время создания компонента, используя это в тесте
const draggable = Cypress.$('#cdk-drop-list-0 > :nth-child(1)')[0]
не будет работать, потому что nth-ребенок не будет присутствовать сразу, только после завершения выборки.
Вместо этого вы можете использовать cy.get()
для обеспечения повторных попыток до времени ожидания (по умолчанию 5 секунд).
cy.get('#cdk-drop-list-0 > :nth-child(1)').then(el => {
const draggable = el[0] // Pick up this
cy.get('#cdk-drop-list-1 > :nth-child(4)').then(el => {
const droppable = el[0] // Drop over this
const coords = droppable.getBoundingClientRect()
draggable.dispatchEvent(new MouseEvent('mousemove'));
draggable.dispatchEvent(new MouseEvent('mousedown'));
draggable.dispatchEvent(new MouseEvent('mousemove', {clientX: 10, clientY: 0}));
draggable.dispatchEvent(new MouseEvent('mousemove', {clientX: coords.x+10, clientY: coords.y+10}));
draggable.dispatchEvent(new MouseEvent('mouseup'));
})
cy.get('#cdk-drop-list-1').should('contain', 'Get to work');
cy.get('#cdk-drop-list-1 > .cdk-drag').eq(3).should('contain', 'Get to work');
})
или я предпочитаю использовать «канарейку», чтобы убедиться, что загрузка завершена, что-то вроде
before(() => {
cy.get('#cdk-drop-list-0 > :nth-child(1)') // Canary - wait 5s for data
})
it('should...', () => {
const draggable = Cypress.$('#cdk-drop-list-0 > :nth-child(1)')[0] // Pick up this
const droppable = Cypress.$('#cdk-drop-list-1 > :nth-child(4)')[0] // Drop over this
...
})
Поддержка машинописи
Предупреждение - это быстрый способ решить проблемы с компилятором Typescript, и его можно улучшить.
const coords: ClientRect = droppable.getBoundingClientRect()
draggable.dispatchEvent(new (<any>MouseEvent)('mousemove'));
draggable.dispatchEvent(new (<any>MouseEvent)('mousedown'));
draggable.dispatchEvent(new (<any>MouseEvent)('mousemove', {clientX: 10.0, clientY: 0.0}));
draggable.dispatchEvent(new (<any>MouseEvent)('mousemove', {clientX: coords.left + 10.0, clientY: coords.top + 10.0}));
draggable.dispatchEvent(new (<any>MouseEvent)('mouseup'));