Использование Selenium для тестирования загрузки файлов всегда было предметом споров. При загрузке файла появляется диалоговое окно файла, и по своей природе Selenium не знает, как обрабатывать системное диалоговое окно. Для браузеров, которые его поддерживают (Chrome, Firefox, Edge, IE11), процесс прост (с помощью sendKeys). Однако, когда вам нужно протестировать Safari и мобильные устройства, sendKeys не будет работать.
Решения, которые я обнаружил, включают использование AutoIt или других сторонних приложений или библиотек. Они могут работать в Windows или Mac, но могут иметь свои проблемы при тестировании в мобильных браузерах. В худшем случае люди игнорируют неподдерживаемые браузеры и прибегают к ручному тестированию. В современном жизненном цикле гибкой разработки программного обеспечения это недопустимо. И лично я бы предпочел ничего не тестировать вручную, если могу.
В этом посте я предлагаю решение для тестирования загрузки в этих неподдерживаемых браузерах, а именно:
- Сафари
- iOS Safari
- Android Chrome
Во-первых, давайте посмотрим, что именно делает sendKeys.
Из протокола Webdriver (sendKeys):
Вывод здесь заключается в том, что когда используется sendKeys, он запускает событие изменения. Поэтому вместо того, чтобы это происходило автоматически с помощью sendKeys, давайте имитируем объект события и вручную активируем событие изменения. В этой демонстрации я буду использовать Angular.
Это моя кнопка выбора файла.
Сначала создайте скрытую кнопку (доступна только в тестовых средах).
<button (click)="onE2EChooseFile($event)" *ngIf="!isEnvProduction" class="display-none" id="file-upload-hidden-button" type="button"></button>
При нажатии этой кнопки вызывается метод onE2EChooseFile, определенный здесь:
onE2EChooseFile(event: any) { const fileName = localStorage.getItem('file'); this.testFileService.getFile(fileName).subscribe((blob) => { const file = new File([blob], fileName); const newEvent = { target: { files: [file], parentElement: { classList: event.target.classList } } }; this.onChange(newEvent); }); }
Этот метод использует службу testFileService, определенную здесь:
export class TestFileService { constructor(private http: HttpClient) {} getFile(fileName: string) Observable<Blob> { return this.http.get(`assets/test-files/${fileName}`, { responseType: 'blob'}); } }
У меня есть действующий тестовый файл, сохраненный в моем репозитории в папке «assets / test-files /».
Собирая все вместе, вот что происходит:
- Я нажимаю скрытую кнопку.
- Моя скрытая кнопка имеет событие onClick, которое вызывает мой метод onE2EChooseFile.
- Мой метод onE2EChooseFile вызывает testFileService, который возвращает объект blob, который соответствует файлу в моей локальной файловой системе.
- Я сохраняю этот объект blob и включаю его в свой фиктивный объект события.
- Я вызываю onChange (передавая ему свое фиктивное событие).
- Результат: файл теперь прикреплен к вводу.
Теперь у нас есть кнопка, которая действует аналогично методу sendKeys. Теперь вы можете возразить, что с помощью этого метода мы не тестируем точный пользовательский поток. Но я бы сказал, что вы не делаете этого и с sendKeys. Кроме того, мы можем предположить, что окно выбора системного файла работает правильно и правильно прикрепляет файл. Следовательно, прикрепление файла через селектор файлов не требуется для целей тестирования e2e.
Теперь, как мы используем это в наших тестах e2e?
Начиная с моего теста, используя Protractor с Jasmine, я вызываю свой метод объекта страницы chooseFile.
describe('File Upload', () => { beforeEach(async () => { // steps to get to Upload page await UploadPage.chooseFile(); }); it('shows the file name', async ()=> { await expect(UploadPage.isPresent(UploadPage.selectedFileNameText)).toBe(true); }); });
Для браузеров, которые его уже поддерживают, используйте sendKeys. В противном случае используйте мой метод clickHiddenButtonForUpload.
async chooseFile(fileName?: string) { if (browser.params.browsersNeedingFileUpload.includes(process.env.BROWSER)) { await this.clickHiddenButtonForUpload(); } else { const absolutePath = super.createFileForUpload(fileName); await super.setText(this.chooseFileButton, absolutePath); } }
Поскольку кнопка скрыта, Selenium не может использовать ее. Поэтому нажимаю через Javascript.
async clickHiddenButtonForUpload() { await browser.executeScript('arguments[0].click();', this.uploadHiddenButton); }
Вот и все. Дайте мне знать, что вы думаете.