diff options
author | dpapad <dpapad@chromium.org> | 2016-03-25 15:35:56 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-03-25 22:37:16 +0000 |
commit | a828668c94c68c08ed6f5838baacef475d842910 (patch) | |
tree | 2461c3a1491eb4d0543f5ccc4a7e23c1fad0c0e1 | |
parent | 5b1e167ce1d26257ec579d9fdcadab8a70360f9c (diff) | |
download | chromium_src-a828668c94c68c08ed6f5838baacef475d842910.zip chromium_src-a828668c94c68c08ed6f5838baacef475d842910.tar.gz chromium_src-a828668c94c68c08ed6f5838baacef475d842910.tar.bz2 |
MD Settings: Certificate manager, hooking up all dialogs.
- When a menu option is selected, dispatching a CertificateActionEvent.
- Listening for that event from certificate_manager_page.js and opening
appropriate dialog.
- Also listening for the certificates-error event, such that the error dialog can
be shown.
BUG=547073
Review URL: https://codereview.chromium.org/1815733004
Cr-Commit-Position: refs/heads/master@{#383388}
9 files changed, 557 insertions, 62 deletions
diff --git a/chrome/browser/resources/settings/certificate_manager_page/ca_trust_edit_dialog.js b/chrome/browser/resources/settings/certificate_manager_page/ca_trust_edit_dialog.js index 019f8fd..3f911ec 100644 --- a/chrome/browser/resources/settings/certificate_manager_page/ca_trust_edit_dialog.js +++ b/chrome/browser/resources/settings/certificate_manager_page/ca_trust_edit_dialog.js @@ -55,13 +55,15 @@ Polymer({ this.$.spinner.active = true; this.browserProxy_.editCaCertificateTrust( this.model.id, this.$.ssl.checked, - this.$.email.checked, this.$.objSign.checked).then(function() { - this.$.spinner.active = false; - this.$.dialog.close(); - }.bind(this), - /** @param {!CertificatesError} error */ - function(error) { - // TODO(dpapad): Display error here. - }); + this.$.email.checked, this.$.objSign.checked).then( + function() { + this.$.spinner.active = false; + this.$.dialog.close(); + }.bind(this), + /** @param {!CertificatesError} error */ + function(error) { + this.$.dialog.close(); + this.fire('certificates-error', error); + }.bind(this)); }, }); diff --git a/chrome/browser/resources/settings/certificate_manager_page/certificate_delete_confirmation_dialog.js b/chrome/browser/resources/settings/certificate_manager_page/certificate_delete_confirmation_dialog.js index e9da85e..595dfd2 100644 --- a/chrome/browser/resources/settings/certificate_manager_page/certificate_delete_confirmation_dialog.js +++ b/chrome/browser/resources/settings/certificate_manager_page/certificate_delete_confirmation_dialog.js @@ -82,12 +82,14 @@ Polymer({ /** @private */ onOkTap_: function() { - this.browserProxy_.deleteCertificate(this.model.id).then(function() { - this.$.dialog.close(); - }.bind(this), - /** @param {!CertificatesError} error */ - function(error) { - // TODO(dpapad): Display error here. - }); + this.browserProxy_.deleteCertificate(this.model.id).then( + function() { + this.$.dialog.close(); + }.bind(this), + /** @param {!CertificatesError} error */ + function(error) { + this.$.dialog.close(); + this.fire('certificates-error', error); + }.bind(this)); }, }); diff --git a/chrome/browser/resources/settings/certificate_manager_page/certificate_manager_page.html b/chrome/browser/resources/settings/certificate_manager_page/certificate_manager_page.html index 8fe34c4..506d1c6 100644 --- a/chrome/browser/resources/settings/certificate_manager_page/certificate_manager_page.html +++ b/chrome/browser/resources/settings/certificate_manager_page/certificate_manager_page.html @@ -8,6 +8,7 @@ <link rel="import" href="chrome://md-settings/certificate_manager_page/certificate_password_decryption_dialog.html"> <link rel="import" href="chrome://md-settings/certificate_manager_page/certificate_password_encryption_dialog.html"> <link rel="import" href="chrome://md-settings/certificate_manager_page/certificates_browser_proxy.html"> +<link rel="import" href="chrome://md-settings/certificate_manager_page/certificates_error_dialog.html"> <dom-module id="settings-certificate-manager-page"> <template> @@ -17,6 +18,31 @@ --paper-tabs-selection-bar-color: blue; } </style> + + <template is="dom-if" if="[[showCaTrustEditDialog_]]" restamp> + <settings-ca-trust-edit-dialog model="[[dialogModel_]]"> + </settings-ca-trust-edit-dialog> + </template> + <template is="dom-if" if="[[showDeleteConfirmationDialog_]]" restamp> + <settings-certificate-delete-confirmation-dialog + model="[[dialogModel_]]" + certificate-type="[[dialogModelCertificateType_]]"> + </settings-certificate-delete-confirmation-dialog> + </template> + <template is="dom-if" if="[[showPasswordEncryptionDialog_]]" restamp> + <settings-certificate-password-encryption-dialog + model="[[dialogModel_]]"> + </settings-certificate-password-encryption-dialog> + </template> + <template is="dom-if" if="[[showPasswordDecryptionDialog_]]" restamp> + <settings-certificate-password-decryption-dialog> + </settings-certificate-password-decryption-dialog> + </template> + <template is="dom-if" if="[[showErrorDialog_]]" restamp> + <settings-certificates-error-dialog model="[[errorDialogModel_]]"> + </settings-certificates-error-dialog> + </template> + <paper-tabs selected="{{selected}}"> <paper-tab>$i18n{certificateManagerYourCertificates}</paper-tab> <paper-tab>$i18n{certificateManagerServers}</paper-tab> diff --git a/chrome/browser/resources/settings/certificate_manager_page/certificate_manager_page.js b/chrome/browser/resources/settings/certificate_manager_page/certificate_manager_page.js index 14fb032f..7614bd5 100644 --- a/chrome/browser/resources/settings/certificate_manager_page/certificate_manager_page.js +++ b/chrome/browser/resources/settings/certificate_manager_page/certificate_manager_page.js @@ -48,6 +48,40 @@ Polymer({ value: settings.CertificateType, readonly: true, }, + + /** @private */ + showCaTrustEditDialog_: Boolean, + + /** @private */ + showDeleteConfirmationDialog_: Boolean, + + /** @private */ + showPasswordEncryptionDialog_: Boolean, + + /** @private */ + showPasswordDecryptionDialog_: Boolean, + + /** @private */ + showErrorDialog_: Boolean, + + /** + * The model to be passed to dialogs that refer to a given certificate. + * @private {?CertificateSubnode} + */ + dialogModel_: Object, + + /** + * The certificate type to be passed to dialogs that refer to a given + * certificate. + * @private {?settings.CertificateType} + */ + dialogModelCertificateType_: String, + + /** + * The model to be passed to the error dialog. + * @private {null|!CertificatesError|!CertificatesImportError} + */ + errorDialogModel_: Object, }, /** @override */ @@ -65,4 +99,62 @@ Polymer({ isTabSelected_: function(selectedIndex, tabIndex) { return selectedIndex == tabIndex; }, + + /** @override */ + ready: function() { + this.addEventListener(settings.CertificateActionEvent, function(event) { + this.dialogModel_ = event.detail.subnode; + this.dialogModelCertificateType_ = event.detail.certificateType; + if (event.detail.action == settings.CertificateAction.EDIT) { + this.openDialog_( + 'settings-ca-trust-edit-dialog', + 'showCaTrustEditDialog_'); + } else if (event.detail.action == settings.CertificateAction.DELETE) { + this.openDialog_( + 'settings-certificate-delete-confirmation-dialog', + 'showDeleteConfirmationDialog_'); + } else if (event.detail.action == + settings.CertificateAction.EXPORT_PERSONAL) { + this.openDialog_( + 'settings-certificate-password-encryption-dialog', + 'showPasswordEncryptionDialog_'); + } else if (event.detail.action == + settings.CertificateAction.IMPORT_PERSONAL) { + this.openDialog_( + 'settings-certificate-password-decryption-dialog', + 'showPasswordDecryptionDialog_'); + } else if (event.detail.action == settings.CertificateAction.IMPORT_CA) { + // TODO(dpapad): Implement this. + } + event.stopPropagation(); + }.bind(this)); + }, + + /** + * Opens a dialog and registers listeners for + * 1) Removing the dialog from the DOM once is closed. + * 2) Showing an error dialog if necessary. + * The listeners are destroyed when the dialog is removed (because of + * 'restamp'); + * + * @param {string} dialogTagName The tag name of the dialog to be shown. + * @param {string} domIfBooleanName The name of the boolean variable + * corresponding to the dialog. + * @private + */ + openDialog_: function(dialogTagName, domIfBooleanName) { + this.set(domIfBooleanName, true); + this.async(function() { + var dialog = this.$$(dialogTagName); + dialog.addEventListener('iron-overlay-closed', function() { + this.set(domIfBooleanName, false); + }.bind(this)); + dialog.addEventListener('certificates-error', function(event) { + this.errorDialogModel_ = event.detail; + this.openDialog_( + 'settings-certificates-error-dialog', + 'showErrorDialog_'); + }.bind(this)); + }.bind(this)); + }, }); diff --git a/chrome/browser/resources/settings/certificate_manager_page/certificate_password_decryption_dialog.js b/chrome/browser/resources/settings/certificate_manager_page/certificate_password_decryption_dialog.js index 9a74530..7eff4c4 100644 --- a/chrome/browser/resources/settings/certificate_manager_page/certificate_password_decryption_dialog.js +++ b/chrome/browser/resources/settings/certificate_manager_page/certificate_password_decryption_dialog.js @@ -38,12 +38,14 @@ Polymer({ /** @private */ onOkTap_: function() { this.browserProxy_.importPersonalCertificatePasswordSelected( - this.password_).then(function() { - this.$.dialog.close(); - }.bind(this), - /** @param {!CertificatesError} error */ - function(error) { - // TODO(dpapad): Display error here. - }); + this.password_).then( + function() { + this.$.dialog.close(); + }.bind(this), + /** @param {!CertificatesError} error */ + function(error) { + this.$.dialog.close(); + this.fire('certificates-error', error); + }.bind(this)); }, }); diff --git a/chrome/browser/resources/settings/certificate_manager_page/certificate_password_encryption_dialog.js b/chrome/browser/resources/settings/certificate_manager_page/certificate_password_encryption_dialog.js index 78bb335..4d6803d 100644 --- a/chrome/browser/resources/settings/certificate_manager_page/certificate_password_encryption_dialog.js +++ b/chrome/browser/resources/settings/certificate_manager_page/certificate_password_encryption_dialog.js @@ -47,13 +47,15 @@ Polymer({ /** @private */ onOkTap_: function() { this.browserProxy_.exportPersonalCertificatePasswordSelected( - this.password_).then(function() { - this.$.dialog.close(); - }.bind(this), - /** @param {!CertificatesError} error */ - function(error) { - // TODO(dpapad): Display error here. - }); + this.password_).then( + function() { + this.$.dialog.close(); + }.bind(this), + /** @param {!CertificatesError} error */ + function(error) { + this.$.dialog.close(); + this.fire('certificates-error', error); + }.bind(this)); }, /** @private */ diff --git a/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.html b/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.html index 94805c7..bd27543 100644 --- a/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.html +++ b/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.html @@ -34,28 +34,28 @@ <div class="container"> <paper-icon-button icon="image:brightness-1"></paper-icon-button> <div class="name">[[model.name]]</div> - <paper-icon-button icon="more-vert" toggles active="{{menuOpened}}"> - </paper-icon-button> + <paper-icon-button id="dots" icon="more-vert" toggles + active="{{menuOpened}}"></paper-icon-button> <!-- TODO(dpapad): Figure out RTL for this menu --> <template is="dom-if" if="[[menuOpened]]"> <iron-dropdown vertical-align="top" horizontal-align="right" opened="{{menuOpened}}"> <div class="dropdown-content"> - <paper-item on-tap="onViewTap_"> + <paper-item id="view" on-tap="onViewTap_"> $i18n{certificateManagerView} </paper-item> - <paper-item hidden$="[[!canEdit_(certificateType)]]" + <paper-item id="edit" hidden$="[[!canEdit_(certificateType)]]" on-tap="onEditTap_"> $i18n{certificateManagerEdit} </paper-item> - <paper-item on-tap="onExportTap_"> + <paper-item id="export" on-tap="onExportTap_"> $i18n{certificateManagerExport} </paper-item> <paper-item hidden$="[[!canImport_(certificateType)]]" on-tap="onImportTap_"> $i18n{certificateManagerImport} </paper-item> - <paper-item hidden$="[[model.readonly]]" + <paper-item id="delete" hidden$="[[model.readonly]]" on-tap="onDeleteTap_"> $i18n{certificateManagerDelete} </paper-item> diff --git a/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.js b/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.js index b750ebb..07c2ab9 100644 --- a/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.js +++ b/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.js @@ -6,6 +6,43 @@ * @fileoverview settings-certificate-subentry represents an SSL certificate * sub-entry. */ + +/** + * The payload of the certificate-action event that is emitted from this + * component. + * @typedef {{ + * action: !settings.CertificateAction, + * subnode: !CertificateSubnode, + * certificateType: !settings.CertificateType + * }} + */ +var CertificateActionEventDetail; + +cr.define('settings', function() { + /** + * Enumeration of actions that require a popup menu to be shown to the user. + * @enum {number} + */ + var CertificateAction = { + DELETE: 0, + EDIT: 1, + EXPORT_PERSONAL: 2, + IMPORT_CA: 3, + IMPORT_PERSONAL: 4, + }; + + /** + * The name of the event that is fired when a menu item is tapped. + * @type {string} + */ + var CertificateActionEvent = 'certificate-action'; + + return { + CertificateAction: CertificateAction, + CertificateActionEvent: CertificateActionEvent, + }; +}); + Polymer({ is: 'settings-certificate-subentry', @@ -21,11 +58,45 @@ Polymer({ browserProxy_: null, /** @override */ - ready: function() { + created: function() { this.browserProxy_ = settings.CertificatesBrowserProxyImpl.getInstance(); }, /** + * Dispatches an event indicating which certificate action was tapped. It is + * used by the parent of this element to display a modal dialog accordingly. + * @param {!settings.CertificateAction} action + * @private + */ + dispatchCertificateActionEvent_: function(action) { + this.fire( + settings.CertificateActionEvent, + /** @type {!CertificateActionEventDetail} */ ({ + action: action, + subnode: this.model, + certificateType: this.certificateType, + })); + }, + + /** + * Handles the case where a call to the browser resulted in a rejected + * promise. + * @param {null|!CertificatesError|!CertificatesImportError} error + * @private + */ + onRejected_: function(error) { + if (error === null) { + // Nothing to do here. Null indicates that the user clicked "cancel" on + // the native file chooser dialog. + return; + } + + // Otherwise propagate the error to the parents, such that a dialog + // displaying the error will be shown. + this.fire('certificates-error', error); + }, + + /** * @param {!Event} event * @private */ @@ -40,7 +111,7 @@ Polymer({ */ onEditTap_: function(event) { this.closePopupMenu_(); - // TODO(dpapad): Open edit dialog. + this.dispatchCertificateActionEvent_(settings.CertificateAction.EDIT); }, /** @@ -49,7 +120,7 @@ Polymer({ */ onDeleteTap_: function(event) { this.closePopupMenu_(); - // TODO(dpapad): Open delete confirmation dialog. + this.dispatchCertificateActionEvent_(settings.CertificateAction.DELETE); }, /** @@ -59,7 +130,12 @@ Polymer({ onExportTap_: function(event) { this.closePopupMenu_(); if (this.certificateType == settings.CertificateType.PERSONAL) { - // TODO(dpapad): Open password encryption dialog. + this.browserProxy_.exportPersonalCertificate(this.model.id).then( + function() { + this.dispatchCertificateActionEvent_( + settings.CertificateAction.EXPORT_PERSONAL); + }.bind(this), + this.onRejected_.bind(this)); } else { this.browserProxy_.exportCertificate(this.model.id); } @@ -73,16 +149,21 @@ Polymer({ this.browserProxy_.importPersonalCertificate(false).then( function(showPasswordPrompt) { if (showPasswordPrompt) { - // TODO(dpapad): Show password decryption dialog. + this.dispatchCertificateActionEvent_( + settings.CertificateAction.IMPORT_PERSONAL); } - }.bind(this)); + }.bind(this), + this.onRejected_.bind(this)); } else if (this.certificateType == settings.CertificateType.CA) { this.browserProxy_.importCaCertificate().then( function(certificateName) { - // TODO(dpapad): Show import dialog. - }.bind(this)); + this.dispatchCertificateActionEvent_( + settings.CertificateAction.IMPORT_CA); + }.bind(this), + this.onRejected_.bind(this)); } else if (this.certificateType == settings.CertificateType.SERVER) { - this.browserProxy_.importServerCertificate(); + this.browserProxy_.importServerCertificate().catch( + this.onRejected_.bind(this)); } }, diff --git a/chrome/test/data/webui/settings/certificate_manager_page_test.js b/chrome/test/data/webui/settings/certificate_manager_page_test.js index b4644ec..bdb71b3 100644 --- a/chrome/test/data/webui/settings/certificate_manager_page_test.js +++ b/chrome/test/data/webui/settings/certificate_manager_page_test.js @@ -16,14 +16,20 @@ cr.define('certificate_manager_page', function() { settings.TestBrowserProxy.call(this, [ 'deleteCertificate', 'editCaCertificateTrust', + 'exportCertificate', + 'exportPersonalCertificate', 'exportPersonalCertificatePasswordSelected', 'getCaCertificateTrust', 'importPersonalCertificatePasswordSelected', 'refreshCertificates', + 'viewCertificate', ]); /** @private {!CaTrustInfo} */ this.caTrustInfo_ = {ssl: true, email: true, objSign: true}; + + /** @private {?CertificatesError} */ + this.certificatesError_ = null; }; TestCertificatesBrowserProxy.prototype = { @@ -47,33 +53,68 @@ cr.define('certificate_manager_page', function() { this.methodCalled('editCaCertificateTrust', { id: id, ssl: ssl, email: email, objSign: objSign, }); - return Promise.resolve(); + return this.fulfillRequest_(); + }, + + /** + * Forces some of the browser proxy methods to start returning errors. + */ + forceCertificatesError: function() { + this.certificatesError_ = /** @type {!CertificatesError} */ ({ + title: 'DummyError', description: 'DummyDescription' + }); + }, + + /** + * @return {!Promise} A promise that is resolved or rejected based on the + * value of |certificatesError_|. + * @private + */ + fulfillRequest_: function() { + return this.certificatesError_ === null ? + Promise.resolve() : Promise.reject(this.certificatesError_); }, /** @override */ deleteCertificate: function(id) { this.methodCalled('deleteCertificate', id); - return Promise.resolve(); + return this.fulfillRequest_(); }, /** @override */ exportPersonalCertificatePasswordSelected: function(password) { this.resolverMap_.get( 'exportPersonalCertificatePasswordSelected').resolve(password); - return Promise.resolve(); + return this.fulfillRequest_(); }, /** @override */ importPersonalCertificatePasswordSelected: function(password) { this.resolverMap_.get( 'importPersonalCertificatePasswordSelected').resolve(password); - return Promise.resolve(); + return this.fulfillRequest_(); }, /** @override */ refreshCertificates: function() { this.methodCalled('refreshCertificates'); }, + + /** @override */ + viewCertificate: function(id) { + this.methodCalled('viewCertificate', id); + }, + + /** @override */ + exportCertificate: function(id) { + this.methodCalled('exportCertificate', id); + }, + + /** @override */ + exportPersonalCertificate: function(id) { + this.methodCalled('exportPersonalCertificate', id); + return Promise.resolve(); + }, }; /** @return {!Certificate} */ @@ -111,6 +152,18 @@ cr.define('certificate_manager_page', function() { MockInteractions.keyEventOn(element, 'input', kSpaceBar); } + /** + * Converts an event occurrence to a promise. + * @param {string} eventType + * @param {!HTMLElement} target + * @return {!Promise} A promise firing once the event occurs. + */ + function eventToPromise(eventType, target) { + return new Promise(function(resolve, reject) { + target.addEventListener(eventType, resolve); + }); + } + function registerCaTrustEditDialogTests() { /** @type {?SettingsCaTrustEditDialogElement} */ var dialog = null; @@ -138,7 +191,7 @@ cr.define('certificate_manager_page', function() { teardown(function() { dialog.remove(); }); - test('Dialog', function() { + test('EditSuccess', function() { return browserProxy.whenCalled('getCaCertificateTrust').then( function(id) { assertEquals(model.id, id); @@ -154,17 +207,31 @@ cr.define('certificate_manager_page', function() { // Simulate clicking 'OK'. MockInteractions.tap(dialog.$.ok); - return browserProxy.whenCalled('editCaCertificateTrust').then( - function(args) { - assertEquals(model.id, args.id); - // Checking that the values sent to C++ are reflecting the - // changes made by the user (toggling all checkboxes). - assertEquals(caTrustInfo.ssl, !args.ssl); - assertEquals(caTrustInfo.email, !args.email); - assertEquals(caTrustInfo.objSign, !args.objSign); - // Check that the dialog is closed. - assertFalse(dialog.$.dialog.opened); - }); + return browserProxy.whenCalled('editCaCertificateTrust'); + }).then( + function(args) { + assertEquals(model.id, args.id); + // Checking that the values sent to C++ are reflecting the + // changes made by the user (toggling all checkboxes). + assertEquals(caTrustInfo.ssl, !args.ssl); + assertEquals(caTrustInfo.email, !args.email); + assertEquals(caTrustInfo.objSign, !args.objSign); + // Check that the dialog is closed. + assertFalse(dialog.$.dialog.opened); + }); + }); + + test('EditError', function() { + browserProxy.forceCertificatesError(); + var whenErrorEventFired = eventToPromise('certificates-error', dialog); + + return browserProxy.whenCalled('getCaCertificateTrust').then( + function() { + MockInteractions.tap(dialog.$.ok); + return browserProxy.whenCalled('editCaCertificateTrust'); + }).then( + function() { + return whenErrorEventFired; }); }); }); @@ -210,6 +277,20 @@ cr.define('certificate_manager_page', function() { assertFalse(dialog.$.dialog.opened); }); }); + + test('DeleteError', function() { + browserProxy.forceCertificatesError(); + var whenErrorEventFired = eventToPromise('certificates-error', dialog); + + // Simulate clicking 'OK'. + MockInteractions.tap(dialog.$.ok); + return browserProxy.whenCalled('deleteCertificate').then( + function(id) { + assertEquals(model.id, id); + // Ensure that the 'error' event was fired. + return whenErrorEventFired; + }); + }); }); } @@ -223,6 +304,8 @@ cr.define('certificate_manager_page', function() { /** @type {!CertificateSubnode} */ var model = createSampleCertificateSubnode(); + var methodName = 'exportPersonalCertificatePasswordSelected'; + suite('CertificatePasswordEncryptionDialogTests', function() { setup(function() { browserProxy = new TestCertificatesBrowserProxy(); @@ -262,13 +345,31 @@ cr.define('certificate_manager_page', function() { // Simulate clicking 'OK'. MockInteractions.tap(dialog.$.ok); - var methodName = 'exportPersonalCertificatePasswordSelected'; return browserProxy.whenCalled(methodName).then(function(password) { assertEquals(passwordInputElement.value, password); // Check that the dialog is closed. assertFalse(dialog.$.dialog.opened); }); }); + + test('EncryptError', function() { + browserProxy.forceCertificatesError(); + + var passwordInputElements = + Polymer.dom(dialog.$.dialog).querySelectorAll('paper-input'); + var passwordInputElement = passwordInputElements[0]; + passwordInputElement.value = 'foopassword'; + var confirmPasswordInputElement = passwordInputElements[1]; + confirmPasswordInputElement.value = passwordInputElement.value; + triggerInputEvent(passwordInputElement); + + var whenErrorEventFired = eventToPromise('certificates-error', dialog); + MockInteractions.tap(dialog.$.ok); + + return browserProxy.whenCalled(methodName).then(function() { + return whenErrorEventFired; + }); + }); }); } @@ -279,6 +380,8 @@ cr.define('certificate_manager_page', function() { /** @type {?TestCertificatesBrowserProxy} */ var browserProxy = null; + var methodName = 'importPersonalCertificatePasswordSelected'; + suite('CertificatePasswordDecryptionDialogTests', function() { setup(function() { browserProxy = new TestCertificatesBrowserProxy(); @@ -308,13 +411,145 @@ cr.define('certificate_manager_page', function() { // Simulate clicking 'OK'. MockInteractions.tap(dialog.$.ok); - var methodName = 'importPersonalCertificatePasswordSelected'; return browserProxy.whenCalled(methodName).then(function(password) { assertEquals(passwordInputElement.value, password); // Check that the dialog is closed. assertFalse(dialog.$.dialog.opened); }); }); + + test('DecryptError', function() { + browserProxy.forceCertificatesError(); + // Simulate entering some password. + var passwordInputElement = + Polymer.dom(dialog.$.dialog).querySelector('paper-input'); + passwordInputElement.value = 'foopassword'; + triggerInputEvent(passwordInputElement); + + var whenErrorEventFired = eventToPromise('certificates-error', dialog); + MockInteractions.tap(dialog.$.ok); + return browserProxy.whenCalled(methodName).then(function() { + return whenErrorEventFired; + }); + }); + }); + } + + function registerCertificateSubentryTests() { + var subentry = null; + + /** @type {?TestCertificatesBrowserProxy} */ + var browserProxy = null; + + /** + * @return {!Promise} A promise firing once a + * |settings.CertificateActionEvent| fires. + */ + var actionEventToPromise = function() { + return eventToPromise(settings.CertificateActionEvent, subentry); + }; + + suite('CertificateManagerPageTests', function() { + setup(function() { + browserProxy = new TestCertificatesBrowserProxy(); + settings.CertificatesBrowserProxyImpl.instance_ = browserProxy; + PolymerTest.clearBody(); + subentry = document.createElement('settings-certificate-subentry'); + subentry.model = createSampleCertificateSubnode(); + subentry.certificateType = settings.CertificateType.PERSONAL; + document.body.appendChild(subentry); + + // Bring up the popup menu for the following tests to use. + MockInteractions.tap(subentry.$.dots); + Polymer.dom.flush(); + }); + + teardown(function() { subentry.remove(); }); + + // Test case where 'View' option is tapped. + test('MenuOptions_View', function() { + var viewButton = subentry.shadowRoot.querySelector('#view'); + MockInteractions.tap(viewButton); + return browserProxy.whenCalled('viewCertificate').then(function(id) { + assertEquals(subentry.model.id, id); + }); + }); + + // Test that the 'Edit' option is only shown when appropriate and that + // once tapped the correct event is fired. + test('MenuOptions_Edit', function() { + var editButton = subentry.shadowRoot.querySelector('#edit'); + // Should be disabled for any certificate type other than + // CertificateType.CA + assertTrue(editButton.hidden); + subentry.certificateType = settings.CertificateType.CA; + assertFalse(editButton.hidden); + + var waitForActionEvent = actionEventToPromise(); + MockInteractions.tap(editButton); + return waitForActionEvent.then(function(event) { + var detail = /** @type {!CertificateActionEventDetail} */ ( + event.detail); + assertEquals(settings.CertificateAction.EDIT, detail.action); + assertEquals(subentry.model.id, detail.subnode.id); + assertEquals(subentry.certificateType, detail.certificateType); + }); + }); + + // Test that the 'Delete' option is only shown when appropriate and that + // once tapped the correct event is fired. + test('MenuOptions_Delete', function() { + subentry.set('model.readonly', true); + + var deleteButton = subentry.shadowRoot.querySelector('#delete'); + // Should be disabled when 'model.readonly' is true. + assertTrue(deleteButton.hidden); + subentry.set('model.readonly', false); + assertFalse(deleteButton.hidden); + + var waitForActionEvent = actionEventToPromise(); + MockInteractions.tap(deleteButton); + return waitForActionEvent.then(function(event) { + var detail = /** @type {!CertificateActionEventDetail} */ ( + event.detail); + assertEquals(settings.CertificateAction.DELETE, detail.action); + assertEquals(subentry.model.id, detail.subnode.id); + }); + }); + + // Test case of exporting a certificate that is not PERSONAL. + test('MenuOptions_Export', function() { + subentry.certificateType = settings.CertificateType.SERVER; + var exportButton = subentry.shadowRoot.querySelector('#export'); + MockInteractions.tap(exportButton); + return browserProxy.whenCalled('exportCertificate').then(function(id) { + assertEquals(subentry.model.id, id); + }); + }); + + // Test case of exporting a PERSONAL certificate. + test('MenuOptions_ExportPersonal', function() { + var waitForActionEvent = actionEventToPromise(); + + var exportButton = subentry.shadowRoot.querySelector('#export'); + MockInteractions.tap(exportButton); + return browserProxy.whenCalled('exportPersonalCertificate').then( + function(id) { + assertEquals(subentry.model.id, id); + + // A promise firing once |settings.CertificateActionEvent| is + // fired. + return waitForActionEvent; + }).then( + function(event) { + var detail = /** @type {!CertificateActionEventDetail} */ ( + event.detail); + assertEquals( + settings.CertificateAction.EXPORT_PERSONAL, + detail.action); + assertEquals(subentry.model.id, detail.subnode.id); + }); + }); }); } @@ -393,6 +628,58 @@ cr.define('certificate_manager_page', function() { assertCertificateListLength(CertificateCategoryIndex.OTHER, 0); }); }); + + /** + * Dispatches a settings.CertificateActionEvent. + * @param {!settings.CertificateAction} action The type of action to + * simulate. + */ + function dispatchCertificateActionEvent(action) { + var eventDetail = /** @type {!CertificateActionEventDetail} */ ({ + action: action, + subnode: createSampleCertificateSubnode(), + certificateType: settings.CertificateType.PERSONAL + }); + page.dispatchEvent(new CustomEvent( + settings.CertificateActionEvent, {detail: eventDetail})); + } + + /** + * Tests that a dialog opens as a response to a + * settings.CertificateActionEvent. + * @param {string} dialogTagName The type of dialog to test. + * @param {!settings.CertificateAction} action The action that is supposed + * to trigger the dialog. + */ + function testDialogOpensOnAction(dialogTagName, action) { + assertFalse(!!page.shadowRoot.querySelector(dialogTagName)); + dispatchCertificateActionEvent(action); + Polymer.dom.flush(); + assertTrue(!!page.shadowRoot.querySelector(dialogTagName)); + } + + test('OpensDialog_DeleteConfirmation', function() { + testDialogOpensOnAction( + 'settings-certificate-delete-confirmation-dialog', + settings.CertificateAction.DELETE); + }); + + test('OpensDialog_PasswordEncryption', function() { + testDialogOpensOnAction( + 'settings-certificate-password-encryption-dialog', + settings.CertificateAction.EXPORT_PERSONAL); + }); + + test('OpensDialog_PasswordDecryption', function() { + testDialogOpensOnAction( + 'settings-certificate-password-decryption-dialog', + settings.CertificateAction.IMPORT_PERSONAL); + }); + + test('OpensDialog_CaTrustEdit', function() { + testDialogOpensOnAction( + 'settings-ca-trust-edit-dialog', settings.CertificateAction.EDIT); + }); }); } @@ -403,6 +690,7 @@ cr.define('certificate_manager_page', function() { registerPasswordEncryptDialogTests(); registerPasswordDecryptDialogTests(); registerPageTests(); + registerCertificateSubentryTests(); }, }; }); |