diff --git a/src/client/automation/playback/upload.js b/src/client/automation/playback/upload.js index 961ad2413e3..487a134147b 100644 --- a/src/client/automation/playback/upload.js +++ b/src/client/automation/playback/upload.js @@ -1,12 +1,37 @@ -import { doUpload } from '../deps/hammerhead'; +import { + doUpload, + eventSandbox, + nativeMethods, +} from '../deps/hammerhead'; import { arrayUtils } from '../deps/testcafe-core'; +const REQUIRED_ATTR_NAME = 'required'; +const FORM_SUBMIT_EVENT_NAME = 'submit'; + export default class UploadAutomation { - constructor (element, paths, createError) { + constructor (element, paths, createError, isNativeAutomation) { this.element = element; this.paths = paths; this.createError = createError; + + if (isNativeAutomation && this.element.form) + this._handleRequiredInput(); + } + + _handleRequiredInput () { + const isRequired = nativeMethods.hasAttribute.call(this.element, REQUIRED_ATTR_NAME); + + if (isRequired) + nativeMethods.removeAttribute.call(this.element, REQUIRED_ATTR_NAME); + + const ensureUploadInputHasRequiredAttribute = () => { + if (isRequired) + nativeMethods.setAttribute.call(this.element, REQUIRED_ATTR_NAME, 'true'); + }; + + eventSandbox.listeners.initElementListening(this.element.form, [FORM_SUBMIT_EVENT_NAME]); + eventSandbox.listeners.addInternalEventAfterListener(this.element.form, [FORM_SUBMIT_EVENT_NAME], ensureUploadInputHasRequiredAttribute); } run () { diff --git a/src/client/driver/command-executors/action-executor/actions-initializer.ts b/src/client/driver/command-executors/action-executor/actions-initializer.ts index e94fae0e1e0..18f8c152fc3 100644 --- a/src/client/driver/command-executors/action-executor/actions-initializer.ts +++ b/src/client/driver/command-executors/action-executor/actions-initializer.ts @@ -177,9 +177,10 @@ function ensureFileInput (element: Node[]): never | void { } ActionExecutor.ACTIONS_HANDLERS[COMMAND_TYPE.setFilesToUpload] = { - create: (command, elements) => { + create: (command, elements, dispatchNativeAutomationEventFn) => { return new UploadAutomation(elements[0], command.filePath, (filePaths: string[], scannedFilePaths: string[]) => new ActionCannotFindFileToUploadError(filePaths, scannedFilePaths), + dispatchNativeAutomationEventFn ); }, diff --git a/test/functional/fixtures/api/es-next/upload/pages/index.html b/test/functional/fixtures/api/es-next/upload/pages/index.html index 899fe7feff4..59dde8caf51 100644 --- a/test/functional/fixtures/api/es-next/upload/pages/index.html +++ b/test/functional/fixtures/api/es-next/upload/pages/index.html @@ -1,13 +1,17 @@ - - - Upload - - -
- - -
- + + + Upload + + +
+ + +
+
+ + +
+ diff --git a/test/functional/fixtures/api/es-next/upload/test.js b/test/functional/fixtures/api/es-next/upload/test.js index 5f1fa346588..0a829b030c9 100644 --- a/test/functional/fixtures/api/es-next/upload/test.js +++ b/test/functional/fixtures/api/es-next/upload/test.js @@ -7,6 +7,10 @@ describe('[API] Upload', function () { return runTests('./testcafe-fixtures/upload-test.js', 'Upload the file', { only: 'chrome' }); }); + it('Should upload the specified file with required input', function () { + return runTests('./testcafe-fixtures/upload-test.js', 'Upload the file with required input', { only: 'chrome' }); + }); + it('Should validate the selector argument', function () { return runTests('./testcafe-fixtures/upload-test.js', 'Invalid selector argument (setFilesToUpload)', { shouldFail: true, diff --git a/test/functional/fixtures/api/es-next/upload/testcafe-fixtures/upload-test.js b/test/functional/fixtures/api/es-next/upload/testcafe-fixtures/upload-test.js index 9f188fbff6e..330a6d2f624 100644 --- a/test/functional/fixtures/api/es-next/upload/testcafe-fixtures/upload-test.js +++ b/test/functional/fixtures/api/es-next/upload/testcafe-fixtures/upload-test.js @@ -39,3 +39,11 @@ test('Invalid selector argument (clearUpload)', async t => { test('Error on upload non-existing file', async t => { await t.setFilesToUpload('#file', ['../dummy-file-1.txt', '../dummy-file-2.txt']); }); + +test('Upload the file with required input', async t => { + await t + .setFilesToUpload('#fileRequired', '../test-data/file1.txt') + .click('#submitRequired'); + + expect(await getUploadedText()).equals('File 1 is uploaded!'); +});