Commit a8eec661 authored by Maggie Cai's avatar Maggie Cai Committed by Commit Bot

[Sharesheet] Use fake static for integration test in files app.

This CL updates the integration test to use fake static to override the
sharesheet apis in the files app.

BUG=1097623

Change-Id: I37c6238bce7a1e0f401d725cab819b9e81d001c3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2359791
Commit-Queue: Maggie Cai <mxcai@chromium.org>
Reviewed-by: default avatarLuciano Pacheco <lucmult@chromium.org>
Cr-Commit-Position: refs/heads/master@{#800132}
parent 977485e8
......@@ -110,12 +110,13 @@ class AppWindowWrapper {
* @return {!Promise<?chrome.app.window.AppWindow>}
*/
async createWindow_(reopen) {
return await new Promise((resolve) => {
return await new Promise((resolve, reject) => {
// Create a window.
chrome.app.window.create(this.url_, this.options_, appWindow => {
this.window_ = appWindow;
if (!appWindow) {
throw new Error(`Failed to create window for ${this.url_}`);
reject(`Failed to create window for ${this.url_}`);
return;
}
// Save the properties.
......
......@@ -549,10 +549,18 @@ test.util.async.renderWindowTextDirectionRTL = (contentWindow, callback) => {
* Maps the path to the replaced attribute to the PrepareFake instance that
* replaced it, to be able to restore the original value.
*
* @private {Object<string, test.util.PrepareFake}
* @private {Object<string, test.util.PrepareFake>}
*/
test.util.backgroundReplacedObjects_ = {};
/**
* Map the appId to a map of all fakes applied in the foreground window e.g.:
* {'files#0': {'chrome.bla.api': FAKE}
*
* @private {Object<string, Object<string, test.util.PrepareFake>>}
*/
test.util.foregroundReplacedObjects_ = {};
/**
* @param {string} attrName
* @param {*} staticValue
......@@ -560,14 +568,16 @@ test.util.backgroundReplacedObjects_ = {};
*/
test.util.staticFakeFactory = (attrName, staticValue) => {
const fake = (...args) => {
console.warn(`staticFake for ${staticValue}`);
setTimeout(() => {
// Find the first callback.
for (const arg of args) {
if (arg instanceof Function) {
if (typeof arg === 'function') {
console.warn(`staticFake for ${attrName} value: ${staticValue}`);
return arg(staticValue);
}
}
throw new Error(`Couldn't find callback for ${attrName}`);
}, 0);
};
return fake;
};
......@@ -582,6 +592,14 @@ test.util.fakes_ = {
'static_fake': test.util.staticFakeFactory,
};
/**
* @enum {string}
*/
test.util.FakeType = {
FOREGROUND_FAKE: 'FOREGROUND_FAKE',
BACKGROUND_FAKE: 'BACKGROUND_FAKE',
};
/**
* Class holds the information for applying and restoring fakes.
*/
......@@ -652,6 +670,12 @@ test.util.PrepareFake = class {
* @private {boolean}
*/
this.prepared_ = false;
/**
* Counter to record the number of times the static fake is called.
* @private {number}
*/
this.callCounter_ = 0;
}
/**
......@@ -667,8 +691,10 @@ test.util.PrepareFake = class {
/**
* Replaces the original implementation with the fake.
* NOTE: It requires prepare() to have been called.
* @param {test.util.FakeType} fakeType Foreground or background fake.
* @param {Window} contentWindow Window to be tested.
*/
replace() {
replace(fakeType, contentWindow) {
const suffix = `for ${this.attrName_} ${this.fakeId_}`;
if (!this.prepared_) {
throw new Error(`PrepareFake prepare() not called ${suffix}`);
......@@ -683,8 +709,11 @@ test.util.PrepareFake = class {
throw new Error(`Missing leafAttrName_ ${suffix}`);
}
this.saveOriginal_();
this.parentObject_[this.leafAttrName_] = this.fake_;
this.saveOriginal_(fakeType, contentWindow);
this.parentObject_[this.leafAttrName_] = (...args) => {
this.fake_(...args);
this.callCounter_++;
};
}
/**
......@@ -701,8 +730,25 @@ test.util.PrepareFake = class {
/**
* Saves the original implementation to be able restore it later.
* @param {test.util.FakeType} fakeType Foreground or background fake.
* @param {Window} contentWindow Window to be tested.
*/
saveOriginal_() {
saveOriginal_(fakeType, contentWindow) {
if (fakeType === test.util.FakeType.FOREGROUND_FAKE) {
const windowFakes =
test.util.foregroundReplacedObjects_[contentWindow.appID] || {};
test.util.foregroundReplacedObjects_[contentWindow.appID] = windowFakes;
// Only save once, otherwise it can save an object that is already fake.
if (!windowFakes[this.attrName_]) {
const original = this.parentObject_[this.leafAttrName_];
this.original_ = original;
windowFakes[this.attrName_] = this;
}
return;
}
if (fakeType === test.util.FakeType.BACKGROUND_FAKE) {
// Only save once, otherwise it can save an object that is already fake.
if (!test.util.backgroundReplacedObjects_[this.attrName_]) {
const original = this.parentObject_[this.leafAttrName_];
......@@ -710,6 +756,7 @@ test.util.PrepareFake = class {
test.util.backgroundReplacedObjects_[this.attrName_] = this;
}
}
}
/**
* Constructs the fake.
......@@ -770,7 +817,7 @@ test.util.sync.backgroundFake = (fakeData) => {
const fake = new test.util.PrepareFake(path, fakeId, window, ...fakeArgs);
fake.prepare();
fake.replace();
fake.replace(test.util.FakeType.BACKGROUND_FAKE, window);
}
};
......@@ -789,44 +836,60 @@ test.util.sync.removeAllBackgroundFakes = () => {
};
/**
* Records if sharesheet was invoked.
* Replaces implementations in the foreground page with fakes.
*
* @private {boolean}
* @param {Window} contentWindow Window to be tested.
* @param {Object{<string, Array>}} fakeData An object mapping the path to the
* object to be replaced and the value is the Array with fake id and additinal
* arguments for the fake constructor, e.g.:
* fakeData = {
* 'chrome.app.window.create' : [
* 'static_fake',
* ['some static value', 'other arg'],
* ]
* }
*
* This will replace the API 'chrome.app.window.create' with a static fake,
* providing the additional data to static fake: ['some static value', 'other
* value'].
*/
test.util.sharesheetInvoked_ = false;
test.util.sync.foregroundFake = (contentWindow, fakeData) => {
for (const [path, mockValue] of Object.entries(fakeData)) {
const fakeId = mockValue[0];
const fakeArgs = mockValue[1] || [];
const fake =
new test.util.PrepareFake(path, fakeId, contentWindow, ...fakeArgs);
fake.prepare();
fake.replace(test.util.FakeType.FOREGROUND_FAKE, contentWindow);
}
};
/**
* Override the sharesheet-related methods in private api for test.
*
* Removes all fakes that were applied to the foreground page.
* @param {Window} contentWindow Window to be tested.
*/
test.util.sync.overrideSharesheetApi = contentWindow => {
test.util.sharesheetInvoked_ = false;
const sharesheetHasTargets = (entries, hasTargets) => {
setTimeout(() => {
hasTargets(true);
}, 0);
};
const invokeSharesheet = (entries, callback) => {
test.util.sharesheetInvoked_ = true;
setTimeout(() => {
callback();
}, 0);
};
test.util.sync.removeAllForegroundFakes = (contentWindow) => {
const savedFakes =
Object.entries(test.util.foregroundReplacedObjects_[contentWindow.appID]);
let removedCount = 0;
for (const [path, fake] of savedFakes) {
fake.restore();
removedCount++;
}
contentWindow.chrome.fileManagerPrivate.sharesheetHasTargets =
sharesheetHasTargets;
contentWindow.chrome.fileManagerPrivate.invokeSharesheet = invokeSharesheet;
return removedCount;
};
/**
* Obtains if the sharesheet invoked.
* Obtains the number of times the static fake api is called.
* @param {Window} contentWindow Window to be tested.
* @return {boolean} Whether sharesheet invoked.
* @param {string} fakedApi Path of the method that is faked.
* @return {number} Number of times the fake api called.
*/
test.util.sync.sharesheetInvoked = contentWindow => {
return test.util.sharesheetInvoked_;
test.util.sync.staticFakeCounter = (contentWindow, fakedApi) => {
const fake =
test.util.foregroundReplacedObjects_[contentWindow.appID][fakedApi];
return fake.callCounter_;
};
// Register the test utils.
......
......@@ -225,10 +225,20 @@ testcase.toolbarMultiMenuFollowsButton = async () => {
testcase.toolbarSharesheetButtonWithSelection = async () => {
const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS);
// Override the sharesheet api for testing.
await remoteCall.callRemoteTestUtil('overrideSharesheetApi', appId, []);
// Fake chrome.fileManagerPrivate.sharesheetHasTargets to return true.
let fakeData = {
'chrome.fileManagerPrivate.sharesheetHasTargets': ['static_fake', [true]],
};
await remoteCall.callRemoteTestUtil('foregroundFake', appId, [fakeData]);
// Fake chrome.fileManagerPrivate.invokeSharesheet.
fakeData = {
'chrome.fileManagerPrivate.invokeSharesheet': ['static_fake', []],
};
await remoteCall.callRemoteTestUtil('foregroundFake', appId, [fakeData]);
const entry = ENTRIES.hello;
// Select an entry in the file list.
chrome.test.assertTrue(await remoteCall.callRemoteTestUtil(
'selectFile', appId, [entry.nameText]));
......@@ -237,8 +247,15 @@ testcase.toolbarSharesheetButtonWithSelection = async () => {
appId, '#sharesheet-button:not([hidden])');
// Check invoke sharesheet is called.
chrome.test.assertTrue(
await remoteCall.callRemoteTestUtil('sharesheetInvoked', appId, []));
chrome.test.assertEq(
1, await remoteCall.callRemoteTestUtil('staticFakeCounter', appId, [
'chrome.fileManagerPrivate.invokeSharesheet'
]));
// Remove fakes.
const removedCount = await remoteCall.callRemoteTestUtil(
'removeAllForegroundFakes', appId, []);
chrome.test.assertEq(2, removedCount);
};
/**
......@@ -249,10 +266,20 @@ testcase.toolbarSharesheetContextMenuWithSelection = async () => {
const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS);
// Override the sharesheet api for testing.
await remoteCall.callRemoteTestUtil('overrideSharesheetApi', appId, []);
// Fake chrome.fileManagerPrivate.sharesheetHasTargets to return true.
let fakeData = {
'chrome.fileManagerPrivate.sharesheetHasTargets': ['static_fake', [true]],
};
await remoteCall.callRemoteTestUtil('foregroundFake', appId, [fakeData]);
// Fake chrome.fileManagerPrivate.invokeSharesheet.
fakeData = {
'chrome.fileManagerPrivate.invokeSharesheet': ['static_fake', []],
};
await remoteCall.callRemoteTestUtil('foregroundFake', appId, [fakeData]);
const entry = ENTRIES.hello;
// Select an entry in the file list.
chrome.test.assertTrue(await remoteCall.callRemoteTestUtil(
'selectFile', appId, [entry.nameText]));
......@@ -271,8 +298,15 @@ testcase.toolbarSharesheetContextMenuWithSelection = async () => {
appId, contextMenu + ' ' + sharesheetEnabled);
// Check invoke sharesheet is called.
chrome.test.assertTrue(
await remoteCall.callRemoteTestUtil('sharesheetInvoked', appId, []));
chrome.test.assertEq(
1, await remoteCall.callRemoteTestUtil('staticFakeCounter', appId, [
'chrome.fileManagerPrivate.invokeSharesheet'
]));
// Remove fakes.
const removedCount = await remoteCall.callRemoteTestUtil(
'removeAllForegroundFakes', appId, []);
chrome.test.assertEq(2, removedCount);
};
/**
......@@ -283,6 +317,12 @@ testcase.toolbarSharesheetNoEntrySelected = async () => {
const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS);
// Fake chrome.fileManagerPrivate.sharesheetHasTargets to return true.
const fakeData = {
'chrome.fileManagerPrivate.sharesheetHasTargets': ['static_fake', [true]],
};
await remoteCall.callRemoteTestUtil('foregroundFake', appId, [fakeData]);
// Right click the list without selecting an entry.
chrome.test.assertTrue(
!!await remoteCall.waitAndRightClick(appId, 'list.list'));
......@@ -297,4 +337,9 @@ testcase.toolbarSharesheetNoEntrySelected = async () => {
appId, contextMenu + ' ' + sharesheetDisabled);
await remoteCall.waitForElement(appId, '#sharesheet-button[hidden]');
// Remove fakes.
const removedCount = await remoteCall.callRemoteTestUtil(
'removeAllForegroundFakes', appId, []);
chrome.test.assertEq(1, removedCount);
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment