Skip to content

Commit

Permalink
personalization: refactor of frontend state
Browse files Browse the repository at this point in the history
Move everything possible into redux state. Add a business logic layer
personalization_api.js to coordinate between API calls and redux store.

Purposely avoid moving navigation state into redux to avoid duplicating
state between URL and redux.
Keep personalization_router.js as owner of navigation related state,
and introduce some public functions on it to navigate.

BUG=NONE
TEST=browser_tests --gtest_filter="PersonalizationApp*"

Cq-Include-Trybots: luci.chrome.try:linux-chromeos-chrome
Change-Id: I562b0f2d70808914e1ef3324f8db8db592716d0e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2940986
Commit-Queue: Jeffrey Young <cowmoo@chromium.org>
Reviewed-by: Xiaohui Chen <xiaohuic@chromium.org>
Cr-Commit-Position: refs/heads/master@{#891470}
  • Loading branch information
cwmoo740 authored and Chromium LUCI CQ committed Jun 11, 2021
1 parent 3c880e7 commit 191b449
Show file tree
Hide file tree
Showing 23 changed files with 830 additions and 581 deletions.
3 changes: 2 additions & 1 deletion chrome/test/data/webui/chromeos/personalization_app/BUILD.gn
Expand Up @@ -7,6 +7,7 @@ import("//third_party/closure_compiler/compile_js.gni")
js_type_check("closure_compile") {
is_polymer3 = true
closure_flags = default_closure_args + [
"language_in=ECMASCRIPT_2020",
"browser_resolver_prefix_replacements=\"chrome://personalization/=../../chromeos/components/personalization_app/resources/\"",
"js_module_root=../../chrome/test/data/webui/",
"js_module_root=./gen/chrome/test/data/webui/",
Expand Down Expand Up @@ -44,7 +45,7 @@ js_library("personalization_app_unified_test") {

js_library("test_personalization_store") {
deps = [
"//chromeos/components/personalization_app/resources/trusted:personalization_actions",
"//chromeos/components/personalization_app/resources/trusted:personalization_reducers",
"//chromeos/components/personalization_app/resources/trusted:personalization_store",
]
}
Expand Down
Expand Up @@ -8,9 +8,8 @@
*/

import {setWallpaperProviderForTesting} from 'chrome://personalization/trusted/mojo_interface_provider.js';
import {PersonalizationState} from 'chrome://personalization/trusted/personalization_actions.js';
import {emptyState} from 'chrome://personalization/trusted/personalization_actions.js';
import {flush, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {emptyState, PersonalizationState} from 'chrome://personalization/trusted/personalization_reducers.js';
import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {assertTrue} from '../../chai_assert.js';
import {flushTasks} from '../../test_util.m.js';
import {TestWallpaperProvider} from './test_mojo_interface_provider.js';
Expand Down
Expand Up @@ -11,7 +11,7 @@
* @suppress {checkTypes}
*/

import {emptyState, reduce} from 'chrome://personalization/trusted/personalization_actions.js';
import {emptyState, reduce} from 'chrome://personalization/trusted/personalization_reducers.js';
import {PersonalizationStore} from 'chrome://personalization/trusted/personalization_store.js';
import {TestStore} from '../../test_store.m.js';

Expand Down
Expand Up @@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import {untrustedOrigin} from 'chrome://personalization/common/constants.js';
import {selectCollection} from 'chrome://personalization/common/iframe_api.js';
import {emptyState} from 'chrome://personalization/trusted/personalization_reducers.js';
import {promisifySendCollectionsForTesting, WallpaperCollections} from 'chrome://personalization/trusted/wallpaper_collections_element.js';
import {assertDeepEquals, assertEquals, assertFalse, assertThrows, assertTrue} from '../../chai_assert.js';
import {assertDeepEquals, assertFalse, assertTrue} from '../../chai_assert.js';
import {waitAfterNextRender} from '../../test_util.m.js';
import {assertWindowObjectsEqual, baseSetup, initElement, teardownElement} from './personalization_app_test_utils.js';
import {TestWallpaperProvider} from './test_mojo_interface_provider.js';
import {TestPersonalizationStore} from './test_personalization_store.js';

export function WallpaperCollectionsTest() {
/** @type {?HTMLElement} */
Expand All @@ -17,46 +17,48 @@ export function WallpaperCollectionsTest() {
/** @type {?TestWallpaperProvider} */
let wallpaperProvider = null;

/** @type {?TestPersonalizationStore} */
let personalizationStore = null;

setup(function() {
wallpaperProvider = baseSetup().wallpaperProvider;
const mocks = baseSetup();
wallpaperProvider = mocks.wallpaperProvider;
personalizationStore = mocks.personalizationStore;
});

teardown(async () => {
await teardownElement(wallpaperCollectionsElement);
wallpaperCollectionsElement = null;
});

test(
'fetches wallpaper collections and shows loading on startup',
async () => {
wallpaperCollectionsElement =
initElement(WallpaperCollections.is, {active: true});
await wallpaperProvider.whenCalled('fetchCollections');
assertEquals(1, wallpaperProvider.getCallCount('fetchCollections'));
test('shows loading on startup', async () => {
wallpaperCollectionsElement = initElement(WallpaperCollections.is);

const spinner = wallpaperCollectionsElement.shadowRoot.querySelector(
'paper-spinner-lite');
assertTrue(!!spinner);
assertTrue(spinner.active);
const spinner = wallpaperCollectionsElement.shadowRoot.querySelector(
'paper-spinner-lite');
assertTrue(!!spinner);
assertTrue(spinner.active);

const iframe =
wallpaperCollectionsElement.shadowRoot.querySelector('iframe');
assertTrue(iframe.hidden);
});
const iframe =
wallpaperCollectionsElement.shadowRoot.querySelector('iframe');
assertTrue(iframe.hidden);
});

test('shows wallpaper collections when loaded', async () => {
const sendCollectionsPromise = promisifySendCollectionsForTesting();
wallpaperCollectionsElement =
initElement(WallpaperCollections.is, {active: true});
wallpaperCollectionsElement = initElement(WallpaperCollections.is);

const spinner = wallpaperCollectionsElement.shadowRoot.querySelector(
'paper-spinner-lite');
assertTrue(!!spinner);
assertTrue(spinner.active);

// Wait for collections to be fetched.
await wallpaperProvider.whenCalled('fetchCollections');
// Wait for iframe to load and |sendCollections| to be called.
personalizationStore.data.loading = {collections: false};
personalizationStore.data.backdrop.collections =
wallpaperProvider.collections;
personalizationStore.notifyObservers();

// Wait for |sendCollections| to be called.
const [target, data] = await sendCollectionsPromise;
await waitAfterNextRender(wallpaperCollectionsElement);

Expand All @@ -71,9 +73,7 @@ export function WallpaperCollectionsTest() {
});

test('shows error when fails to load', async () => {
wallpaperProvider.setCollectionsToFail();
wallpaperCollectionsElement =
initElement(WallpaperCollections.is, {active: true});
wallpaperCollectionsElement = initElement(WallpaperCollections.is);

const spinner = wallpaperCollectionsElement.shadowRoot.querySelector(
'paper-spinner-lite');
Expand All @@ -84,7 +84,9 @@ export function WallpaperCollectionsTest() {
wallpaperCollectionsElement.shadowRoot.querySelector('#error');
assertTrue(error.hidden);

await wallpaperProvider.whenCalled('fetchCollections');
personalizationStore.data.loading = {collections: false};
personalizationStore.data.backdrop.collections = null;
personalizationStore.notifyObservers();
await waitAfterNextRender(wallpaperCollectionsElement);

assertFalse(spinner.active);
Expand All @@ -95,58 +97,38 @@ export function WallpaperCollectionsTest() {
wallpaperCollectionsElement.shadowRoot.querySelector('iframe').hidden);
});

test(
'calls selectCollection callback when SelectCollectionEvent is received',
async () => {
const sendCollectionsPromise = promisifySendCollectionsForTesting();
wallpaperCollectionsElement =
initElement(WallpaperCollections.is, {active: true});
const selectCollectionPromise = new Promise((resolve) => {
wallpaperCollectionsElement.selectCollection = resolve;
const original = wallpaperCollectionsElement.onCollectionSelected_;
function patched(event) {
// Rewrite event to make it look as if coming from untrusted origin.
original.call(
wallpaperCollectionsElement,
{data: event.data, origin: untrustedOrigin});
}
window.removeEventListener('message', original);
window.addEventListener('message', patched, {once: true});
});
await sendCollectionsPromise;
await waitAfterNextRender(wallpaperCollectionsElement);

selectCollection(window, 'id_0');
const id = await selectCollectionPromise;
assertEquals('id_0', id);
});

test(
'throws error when invalid SelectCollectionEvent is received',
async () => {
const sendCollectionsPromise = promisifySendCollectionsForTesting();
wallpaperCollectionsElement =
initElement(WallpaperCollections.is, {active: true});
const original = wallpaperCollectionsElement.onCollectionSelected_;
const selectCollectionPromise = new Promise((resolve) => {
function patched(event) {
// Rewrite event to make it look as if coming from untrusted origin.
assertThrows(
() => original.call(
wallpaperCollectionsElement,
{data: event.data, origin: untrustedOrigin}),
'Assertion failed: No valid selection found in choices');
resolve();
}
window.removeEventListener('message', original);
window.addEventListener('message', patched, {once: true});
});

await sendCollectionsPromise;
await waitAfterNextRender(wallpaperCollectionsElement);

selectCollection(window, 'does_not_exist');
// Wait for the message handler |patched| to run.
await selectCollectionPromise;
});
test('loads backdrop data and saves to store', async () => {
// Make sure state starts at expected value.
assertDeepEquals(emptyState(), personalizationStore.data);
// Actually run the reducers.
personalizationStore.setReducersEnabled(true);

const sendCollectionsPromise = promisifySendCollectionsForTesting();
wallpaperCollectionsElement = initElement(WallpaperCollections.is);

const [_, data] = await sendCollectionsPromise;
assertDeepEquals(wallpaperProvider.collections, data);

assertDeepEquals(
{
collections: wallpaperProvider.collections,
images: {
'id_0': wallpaperProvider.images,
'id_1': wallpaperProvider.images,
},
},
personalizationStore.data.backdrop,
);
assertDeepEquals(
{
...emptyState().loading,
collections: false,
images: {
'id_0': false,
'id_1': false,
},
},
personalizationStore.data.loading,
);
});
}

0 comments on commit 191b449

Please sign in to comment.