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 { ...@@ -110,12 +110,13 @@ class AppWindowWrapper {
* @return {!Promise<?chrome.app.window.AppWindow>} * @return {!Promise<?chrome.app.window.AppWindow>}
*/ */
async createWindow_(reopen) { async createWindow_(reopen) {
return await new Promise((resolve) => { return await new Promise((resolve, reject) => {
// Create a window. // Create a window.
chrome.app.window.create(this.url_, this.options_, appWindow => { chrome.app.window.create(this.url_, this.options_, appWindow => {
this.window_ = appWindow; this.window_ = appWindow;
if (!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. // Save the properties.
......
...@@ -549,10 +549,18 @@ test.util.async.renderWindowTextDirectionRTL = (contentWindow, callback) => { ...@@ -549,10 +549,18 @@ test.util.async.renderWindowTextDirectionRTL = (contentWindow, callback) => {
* Maps the path to the replaced attribute to the PrepareFake instance that * Maps the path to the replaced attribute to the PrepareFake instance that
* replaced it, to be able to restore the original value. * 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_ = {}; 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 {string} attrName
* @param {*} staticValue * @param {*} staticValue
...@@ -560,14 +568,16 @@ test.util.backgroundReplacedObjects_ = {}; ...@@ -560,14 +568,16 @@ test.util.backgroundReplacedObjects_ = {};
*/ */
test.util.staticFakeFactory = (attrName, staticValue) => { test.util.staticFakeFactory = (attrName, staticValue) => {
const fake = (...args) => { const fake = (...args) => {
console.warn(`staticFake for ${staticValue}`); setTimeout(() => {
// Find the first callback. // Find the first callback.
for (const arg of args) { for (const arg of args) {
if (arg instanceof Function) { if (typeof arg === 'function') {
return arg(staticValue); console.warn(`staticFake for ${attrName} value: ${staticValue}`);
return arg(staticValue);
}
} }
} throw new Error(`Couldn't find callback for ${attrName}`);
throw new Error(`Couldn't find callback for ${attrName}`); }, 0);
}; };
return fake; return fake;
}; };
...@@ -582,6 +592,14 @@ test.util.fakes_ = { ...@@ -582,6 +592,14 @@ test.util.fakes_ = {
'static_fake': test.util.staticFakeFactory, '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. * Class holds the information for applying and restoring fakes.
*/ */
...@@ -652,6 +670,12 @@ test.util.PrepareFake = class { ...@@ -652,6 +670,12 @@ test.util.PrepareFake = class {
* @private {boolean} * @private {boolean}
*/ */
this.prepared_ = false; 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 { ...@@ -667,8 +691,10 @@ test.util.PrepareFake = class {
/** /**
* Replaces the original implementation with the fake. * Replaces the original implementation with the fake.
* NOTE: It requires prepare() to have been called. * 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_}`; const suffix = `for ${this.attrName_} ${this.fakeId_}`;
if (!this.prepared_) { if (!this.prepared_) {
throw new Error(`PrepareFake prepare() not called ${suffix}`); throw new Error(`PrepareFake prepare() not called ${suffix}`);
...@@ -683,8 +709,11 @@ test.util.PrepareFake = class { ...@@ -683,8 +709,11 @@ test.util.PrepareFake = class {
throw new Error(`Missing leafAttrName_ ${suffix}`); throw new Error(`Missing leafAttrName_ ${suffix}`);
} }
this.saveOriginal_(); this.saveOriginal_(fakeType, contentWindow);
this.parentObject_[this.leafAttrName_] = this.fake_; this.parentObject_[this.leafAttrName_] = (...args) => {
this.fake_(...args);
this.callCounter_++;
};
} }
/** /**
...@@ -701,13 +730,31 @@ test.util.PrepareFake = class { ...@@ -701,13 +730,31 @@ test.util.PrepareFake = class {
/** /**
* Saves the original implementation to be able restore it later. * 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) {
// Only save once, otherwise it can save an object that is already fake. if (fakeType === test.util.FakeType.FOREGROUND_FAKE) {
if (!test.util.backgroundReplacedObjects_[this.attrName_]) { const windowFakes =
const original = this.parentObject_[this.leafAttrName_]; test.util.foregroundReplacedObjects_[contentWindow.appID] || {};
this.original_ = original; test.util.foregroundReplacedObjects_[contentWindow.appID] = windowFakes;
test.util.backgroundReplacedObjects_[this.attrName_] = this;
// 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_];
this.original_ = original;
test.util.backgroundReplacedObjects_[this.attrName_] = this;
}
} }
} }
...@@ -770,7 +817,7 @@ test.util.sync.backgroundFake = (fakeData) => { ...@@ -770,7 +817,7 @@ test.util.sync.backgroundFake = (fakeData) => {
const fake = new test.util.PrepareFake(path, fakeId, window, ...fakeArgs); const fake = new test.util.PrepareFake(path, fakeId, window, ...fakeArgs);
fake.prepare(); fake.prepare();
fake.replace(); fake.replace(test.util.FakeType.BACKGROUND_FAKE, window);
} }
}; };
...@@ -789,44 +836,60 @@ test.util.sync.removeAllBackgroundFakes = () => { ...@@ -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. * @param {Window} contentWindow Window to be tested.
*/ */
test.util.sync.overrideSharesheetApi = contentWindow => { test.util.sync.removeAllForegroundFakes = (contentWindow) => {
test.util.sharesheetInvoked_ = false; const savedFakes =
const sharesheetHasTargets = (entries, hasTargets) => { Object.entries(test.util.foregroundReplacedObjects_[contentWindow.appID]);
setTimeout(() => { let removedCount = 0;
hasTargets(true); for (const [path, fake] of savedFakes) {
}, 0); fake.restore();
}; removedCount++;
}
const invokeSharesheet = (entries, callback) => {
test.util.sharesheetInvoked_ = true;
setTimeout(() => {
callback();
}, 0);
};
contentWindow.chrome.fileManagerPrivate.sharesheetHasTargets = return removedCount;
sharesheetHasTargets;
contentWindow.chrome.fileManagerPrivate.invokeSharesheet = invokeSharesheet;
}; };
/** /**
* Obtains if the sharesheet invoked. * Obtains the number of times the static fake api is called.
* @param {Window} contentWindow Window to be tested. * @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 => { test.util.sync.staticFakeCounter = (contentWindow, fakedApi) => {
return test.util.sharesheetInvoked_; const fake =
test.util.foregroundReplacedObjects_[contentWindow.appID][fakedApi];
return fake.callCounter_;
}; };
// Register the test utils. // Register the test utils.
......
...@@ -225,10 +225,20 @@ testcase.toolbarMultiMenuFollowsButton = async () => { ...@@ -225,10 +225,20 @@ testcase.toolbarMultiMenuFollowsButton = async () => {
testcase.toolbarSharesheetButtonWithSelection = async () => { testcase.toolbarSharesheetButtonWithSelection = async () => {
const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS); const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS);
// Override the sharesheet api for testing. // Fake chrome.fileManagerPrivate.sharesheetHasTargets to return true.
await remoteCall.callRemoteTestUtil('overrideSharesheetApi', appId, []); 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; const entry = ENTRIES.hello;
// Select an entry in the file list. // Select an entry in the file list.
chrome.test.assertTrue(await remoteCall.callRemoteTestUtil( chrome.test.assertTrue(await remoteCall.callRemoteTestUtil(
'selectFile', appId, [entry.nameText])); 'selectFile', appId, [entry.nameText]));
...@@ -237,8 +247,15 @@ testcase.toolbarSharesheetButtonWithSelection = async () => { ...@@ -237,8 +247,15 @@ testcase.toolbarSharesheetButtonWithSelection = async () => {
appId, '#sharesheet-button:not([hidden])'); appId, '#sharesheet-button:not([hidden])');
// Check invoke sharesheet is called. // Check invoke sharesheet is called.
chrome.test.assertTrue( chrome.test.assertEq(
await remoteCall.callRemoteTestUtil('sharesheetInvoked', appId, [])); 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 () => { ...@@ -249,10 +266,20 @@ testcase.toolbarSharesheetContextMenuWithSelection = async () => {
const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS); const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS);
// Override the sharesheet api for testing. // Fake chrome.fileManagerPrivate.sharesheetHasTargets to return true.
await remoteCall.callRemoteTestUtil('overrideSharesheetApi', appId, []); 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; const entry = ENTRIES.hello;
// Select an entry in the file list. // Select an entry in the file list.
chrome.test.assertTrue(await remoteCall.callRemoteTestUtil( chrome.test.assertTrue(await remoteCall.callRemoteTestUtil(
'selectFile', appId, [entry.nameText])); 'selectFile', appId, [entry.nameText]));
...@@ -271,8 +298,15 @@ testcase.toolbarSharesheetContextMenuWithSelection = async () => { ...@@ -271,8 +298,15 @@ testcase.toolbarSharesheetContextMenuWithSelection = async () => {
appId, contextMenu + ' ' + sharesheetEnabled); appId, contextMenu + ' ' + sharesheetEnabled);
// Check invoke sharesheet is called. // Check invoke sharesheet is called.
chrome.test.assertTrue( chrome.test.assertEq(
await remoteCall.callRemoteTestUtil('sharesheetInvoked', appId, [])); 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 () => { ...@@ -283,6 +317,12 @@ testcase.toolbarSharesheetNoEntrySelected = async () => {
const appId = await setupAndWaitUntilReady(RootPath.DOWNLOADS); 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. // Right click the list without selecting an entry.
chrome.test.assertTrue( chrome.test.assertTrue(
!!await remoteCall.waitAndRightClick(appId, 'list.list')); !!await remoteCall.waitAndRightClick(appId, 'list.list'));
...@@ -297,4 +337,9 @@ testcase.toolbarSharesheetNoEntrySelected = async () => { ...@@ -297,4 +337,9 @@ testcase.toolbarSharesheetNoEntrySelected = async () => {
appId, contextMenu + ' ' + sharesheetDisabled); appId, contextMenu + ' ' + sharesheetDisabled);
await remoteCall.waitForElement(appId, '#sharesheet-button[hidden]'); 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