// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/** @fileoverview Suite of tests for extension-pack-dialog. */
import 'chrome://extensions/extensions.js';
import type {ExtensionsPackDialogAlertElement, ExtensionsPackDialogElement, PackDialogDelegate} from 'chrome://extensions/extensions.js';
import {PromiseResolver} from 'chrome://resources/js/promise_resolver.js';
import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {assertEquals, assertFalse, assertTrue} from 'chrome://webui-test/chai_assert.js';
import {flushTasks} from 'chrome://webui-test/polymer_test_util.js';
import {eventToPromise} from 'chrome://webui-test/test_util.js';
import {isElementVisible} from './test_util.js';
class MockDelegate implements PackDialogDelegate {
rootPromise: PromiseResolver<string>|null = null;
keyPromise: PromiseResolver<string>|null = null;
rootPath: string|null = null;
keyPath: string|null = null;
flag: number|undefined = 0;
packPromise: PromiseResolver<chrome.developerPrivate.PackDirectoryResponse>|
null = null;
choosePackRootDirectory() {
this.rootPromise = new PromiseResolver();
return this.rootPromise.promise;
}
choosePrivateKeyPath() {
this.keyPromise = new PromiseResolver();
return this.keyPromise.promise;
}
packExtension(rootPath: string, keyPath: string, flag?: number) {
this.rootPath = rootPath;
this.keyPath = keyPath;
this.flag = flag;
this.packPromise = new PromiseResolver();
return this.packPromise.promise;
}
}
suite('ExtensionPackDialogTests', function() {
let packDialog: ExtensionsPackDialogElement;
let mockDelegate: MockDelegate;
setup(function() {
document.body.innerHTML = window.trustedTypes!.emptyHTML;
mockDelegate = new MockDelegate();
packDialog = document.createElement('extensions-pack-dialog');
packDialog.delegate = mockDelegate;
document.body.appendChild(packDialog);
});
test('Interaction', function() {
const dialogElement = packDialog.$.dialog.getNative();
assertTrue(isElementVisible(dialogElement));
assertEquals('', packDialog.$.rootDir.value);
packDialog.$.rootDirBrowse.click();
assertTrue(!!mockDelegate.rootPromise);
assertEquals('', packDialog.$.rootDir.value);
const kRootPath = 'this/is/a/path';
const promises = [];
promises.push(mockDelegate.rootPromise.promise.then(function() {
assertEquals(kRootPath, packDialog.$.rootDir.value);
}));
flush();
assertEquals('', packDialog.$.keyFile.value);
packDialog.$.keyFileBrowse.click();
assertTrue(!!mockDelegate.keyPromise);
assertEquals('', packDialog.$.keyFile.value);
const kKeyPath = 'here/is/another/path';
promises.push(mockDelegate.keyPromise.promise.then(function() {
assertEquals(kKeyPath, packDialog.$.keyFile.value);
}));
mockDelegate.rootPromise.resolve(kRootPath);
mockDelegate.keyPromise.resolve(kKeyPath);
return Promise.all(promises).then(function() {
packDialog.shadowRoot!.querySelector<HTMLElement>(
'.action-button')!.click();
assertEquals(kRootPath, mockDelegate.rootPath);
assertEquals(kKeyPath, mockDelegate.keyPath);
});
});
test('PackSuccess', function() {
const dialogElement = packDialog.$.dialog.getNative();
let packDialogAlert: ExtensionsPackDialogAlertElement;
let alertElement: HTMLDialogElement;
assertTrue(isElementVisible(dialogElement));
const kRootPath = 'this/is/a/path';
packDialog.$.rootDirBrowse.click();
mockDelegate.rootPromise!.resolve(kRootPath);
return mockDelegate.rootPromise!.promise
.then(() => {
assertEquals(kRootPath, packDialog.$.rootDir.value);
packDialog.shadowRoot!.querySelector<HTMLElement>(
'.action-button')!.click();
return flushTasks();
})
.then(() => {
mockDelegate.packPromise!.resolve({
message: '',
item_path: '',
pem_path: '',
override_flags: 0,
status: chrome.developerPrivate.PackStatus.SUCCESS,
});
return mockDelegate.packPromise!.promise;
})
.then(() => {
packDialogAlert = packDialog.shadowRoot!.querySelector(
'extensions-pack-dialog-alert')!;
alertElement = packDialogAlert.$.dialog.getNative();
assertTrue(isElementVisible(alertElement));
assertTrue(isElementVisible(dialogElement));
assertTrue(
!!packDialogAlert.shadowRoot!.querySelector('.action-button'));
const wait = eventToPromise('close', dialogElement);
// After 'ok', both dialogs should be closed.
packDialogAlert.shadowRoot!
.querySelector<HTMLElement>('.action-button')!.click();
return wait;
})
.then(() => {
assertFalse(isElementVisible(alertElement));
assertFalse(isElementVisible(dialogElement));
});
});
test('PackError', function() {
const dialogElement = packDialog.$.dialog.getNative();
let packDialogAlert: ExtensionsPackDialogAlertElement;
let alertElement: HTMLDialogElement;
assertTrue(isElementVisible(dialogElement));
const kRootPath = 'this/is/a/path';
packDialog.$.rootDirBrowse.click();
mockDelegate.rootPromise!.resolve(kRootPath);
return mockDelegate.rootPromise!.promise
.then(() => {
assertEquals(kRootPath, packDialog.$.rootDir.value);
packDialog.shadowRoot!.querySelector<HTMLElement>(
'.action-button')!.click();
return flushTasks();
})
.then(() => {
mockDelegate.packPromise!.resolve({
message: '',
item_path: '',
pem_path: '',
override_flags: 0,
status: chrome.developerPrivate.PackStatus.ERROR,
});
return mockDelegate.packPromise!.promise;
})
.then(() => {
// Make sure new alert and the appropriate buttons are visible.
packDialogAlert = packDialog.shadowRoot!.querySelector(
'extensions-pack-dialog-alert')!;
alertElement = packDialogAlert.$.dialog.getNative();
assertTrue(isElementVisible(alertElement));
assertTrue(isElementVisible(dialogElement));
assertTrue(
!!packDialogAlert.shadowRoot!.querySelector('.action-button'));
// After cancel, original dialog is still open and values unchanged.
packDialogAlert.shadowRoot!
.querySelector<HTMLElement>('.action-button')!.click();
flush();
assertFalse(isElementVisible(alertElement));
assertTrue(isElementVisible(dialogElement));
assertEquals(kRootPath, packDialog.$.rootDir.value);
});
});
test('PackWarning', function() {
const dialogElement = packDialog.$.dialog.getNative();
let packDialogAlert: ExtensionsPackDialogAlertElement;
let alertElement: HTMLDialogElement;
assertTrue(isElementVisible(dialogElement));
const kRootPath = 'this/is/a/path';
const kOverrideFlags = 1;
packDialog.$.rootDirBrowse.click();
mockDelegate.rootPromise!.resolve(kRootPath);
return mockDelegate.rootPromise!.promise
.then(() => {
assertEquals(kRootPath, packDialog.$.rootDir.value);
packDialog.shadowRoot!.querySelector<HTMLElement>(
'.action-button')!.click();
return flushTasks();
})
.then(() => {
mockDelegate.packPromise!.resolve({
message: '',
status: chrome.developerPrivate.PackStatus.WARNING,
item_path: 'item_path',
pem_path: 'pem_path',
override_flags: kOverrideFlags,
});
return mockDelegate.packPromise!.promise;
})
.then(() => {
// Clear the flag. We expect it to change later.
mockDelegate.flag = 0;
// Make sure new alert and the appropriate buttons are visible.
packDialogAlert = packDialog.shadowRoot!.querySelector(
'extensions-pack-dialog-alert')!;
alertElement = packDialogAlert.$.dialog.getNative();
assertTrue(isElementVisible(alertElement));
assertTrue(isElementVisible(dialogElement));
assertFalse(
packDialogAlert.shadowRoot!
.querySelector<HTMLElement>('.cancel-button')!.hidden);
assertFalse(
packDialogAlert.shadowRoot!
.querySelector<HTMLElement>('.action-button')!.hidden);
// Make sure "proceed anyway" try to pack extension again.
const whenClosed = eventToPromise('close', packDialogAlert);
packDialogAlert.shadowRoot!
.querySelector<HTMLElement>('.action-button')!.click();
return whenClosed;
})
.then(() => {
// Make sure packExtension is called again with the right params.
assertFalse(isElementVisible(alertElement));
assertEquals(mockDelegate.flag, kOverrideFlags);
});
});
});