/** * Test for LoginManagerChild._getFormFields. */ "use strict"; XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]); const { LoginFormFactory } = ChromeUtils.import( "resource://gre/modules/LoginFormFactory.jsm" ); const LMCBackstagePass = ChromeUtils.import( "resource://gre/modules/LoginManagerChild.jsm", null ); const { LoginManagerChild } = LMCBackstagePass; const TESTENVIRONMENTS = { filledPW1WithGeneratedPassword: { generatedPWFieldSelectors: ["#pw1"], }, }; const TESTCASES = [ { description: "1 password field outside of a
`, returnedFieldIDs: { usernameField: "un1", newPasswordField: "pw1", oldPasswordField: null, }, skipEmptyFields: undefined, extraTestEnvironments: [TESTENVIRONMENTS.filledPW1WithGeneratedPassword], }, { description: "5 empty password fields outside of a `, returnedFieldIDs: { usernameField: null, newPasswordField: "pw1", oldPasswordField: null, }, skipEmptyFields: undefined, extraTestEnvironments: [TESTENVIRONMENTS.filledPW1WithGeneratedPassword], }, { description: "Form with 2 password fields", document: ``, returnedFieldIDs: { usernameField: null, newPasswordField: "pw1", oldPasswordField: null, }, skipEmptyFields: undefined, extraTestEnvironments: [TESTENVIRONMENTS.filledPW1WithGeneratedPassword], }, { description: "1 password field in a form, 1 outside (not processed)", document: ``, returnedFieldIDs: { usernameField: null, newPasswordField: "pw1", oldPasswordField: null, }, skipEmptyFields: undefined, extraTestEnvironments: [TESTENVIRONMENTS.filledPW1WithGeneratedPassword], }, { description: "1 password field in a form, 1 text field outside (not processed)", document: ``, returnedFieldIDs: { usernameField: null, newPasswordField: "pw1", oldPasswordField: null, }, skipEmptyFields: undefined, extraTestEnvironments: [TESTENVIRONMENTS.filledPW1WithGeneratedPassword], }, { description: "1 text field in a form, 1 password field outside (not processed)", document: ``, returnedFieldIDs: { usernameField: null, newPasswordField: null, oldPasswordField: null, }, skipEmptyFields: undefined, extraTestEnvironments: [TESTENVIRONMENTS.filledPW1WithGeneratedPassword], }, { description: "2 password fields outside of a `, returnedFieldIDs: { usernameField: null, newPasswordField: "pw1", oldPasswordField: null, }, skipEmptyFields: undefined, extraTestEnvironments: [TESTENVIRONMENTS.filledPW1WithGeneratedPassword], }, { description: "2 password fields outside of a `, returnedFieldIDs: { usernameField: null, newPasswordField: null, oldPasswordField: null, }, skipEmptyFields: true, extraTestEnvironments: [TESTENVIRONMENTS.filledPW1WithGeneratedPassword], }, { description: "2 password fields outside of a `, returnedFieldIDs: { usernameField: null, newPasswordField: "pw1", oldPasswordField: null, }, skipEmptyFields: true, extraTestEnvironments: [TESTENVIRONMENTS.filledPW1WithGeneratedPassword], }, { description: "3 password fields, 2nd and 3rd are filled with generated passwords", document: ` `, returnedFieldIDs: { usernameField: null, newPasswordField: "pw2", confirmPasswordField: "pw3", oldPasswordField: "pw1", }, skipEmptyFields: undefined, generatedPWFieldSelectors: ["#pw2", "#pw3"], // this test doesn't make sense to run with different filled generated password values extraTestEnvironments: [], }, ]; const TEST_ENVIRONMENT_CASES = TESTCASES.flatMap(tc => { let arr = [tc]; // also run this test case with this different state for (let env of tc.extraTestEnvironments) { arr.push({ ...tc, ...env, }); } return arr; }); for (let tc of TEST_ENVIRONMENT_CASES) { info("Sanity checking the testcase: " + tc.description); (function() { let testcase = tc; add_task(async function() { info("Starting testcase: " + testcase.description); info("Document string: " + testcase.document); let document = MockDocument.createTestDocument( "http://localhost:8080/test/", testcase.document ); let input = document.querySelector("input"); MockDocument.mockOwnerDocumentProperty( input, document, "http://localhost:8080/test/" ); let formLike = LoginFormFactory.createFromField(input); if (testcase.beforeGetFunction) { await testcase.beforeGetFunction(document, formLike); } let lmc = new LoginManagerChild(); let loginFormState = lmc.stateForDocument(formLike.ownerDocument); loginFormState.generatedPasswordFields = _generateDocStateFromTestCase( testcase, document ); let actual = lmc._getFormFields( formLike, testcase.skipEmptyFields, new Set() ); [ "usernameField", "newPasswordField", "oldPasswordField", "confirmPasswordField", ].forEach(fieldName => { Assert.ok( fieldName in actual, "_getFormFields return value includes " + fieldName ); }); for (let key of Object.keys(testcase.returnedFieldIDs)) { let expectedID = testcase.returnedFieldIDs[key]; if (expectedID === null) { Assert.strictEqual( actual[key], expectedID, "Check returned field " + key + " is null" ); } else { Assert.strictEqual( actual[key].id, expectedID, "Check returned field " + key + " ID" ); } } }); })(); } function _generateDocStateFromTestCase(stateProperties, document) { // prepopulate the document form state LMC holds with // any generated password fields defined in this testcase let generatedPasswordFields = new Set(); info( "stateProperties has generatedPWFieldSelectors: " + stateProperties.generatedPWFieldSelectors?.join(", ") ); if (stateProperties.generatedPWFieldSelectors?.length) { stateProperties.generatedPWFieldSelectors.forEach(sel => { let field = document.querySelector(sel); if (field) { generatedPasswordFields.add(field); } else { info(`No password field: ${sel} found in this document`); } }); } return generatedPasswordFields; }