Commit 295eaa47 authored by Caroline Rising's avatar Caroline Rising Committed by Commit Bot

Add a delete and mark as read/unread button to Read later menu items.

This change is behind the kReadLater feature flag and uses styles shared
with the Tab Search feature. The delete button removes entries from the
reading list model and the mark as read/unread button updates the
status. Both buttons will trigger an update to the menu items so changes
are seen as they are triggered.

Bug: 1109316
Change-Id: Iaa093427c4f9be78901833eca3fd1dabec8ec1b4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2422246
Commit-Queue: Caroline Rising <corising@chromium.org>
Reviewed-by: default avatarAlex Gough <ajgo@chromium.org>
Reviewed-by: default avatardpapad <dpapad@chromium.org>
Cr-Commit-Position: refs/heads/master@{#810050}
parent fee75f6e
...@@ -5693,6 +5693,12 @@ Keep your key file in a safe place. You will need it to create new versions of y ...@@ -5693,6 +5693,12 @@ Keep your key file in a safe place. You will need it to create new versions of y
<message name="IDS_READ_LATER_MENU_READ_HEADER" desc="Header for section of read Read later items."> <message name="IDS_READ_LATER_MENU_READ_HEADER" desc="Header for section of read Read later items.">
PAGES YOU'VE READ PAGES YOU'VE READ
</message> </message>
<message name="IDS_READ_LATER_MENU_TOOLTIP_MARK_AS_READ" desc="Tooltip for the button to mark a read later entry as read.">
Mark as read
</message>
<message name="IDS_READ_LATER_MENU_TOOLTIP_MARK_AS_UNREAD" desc="Tooltip for the button to mark a read later entry as unread.">
Mark as unread
</message>
<!--Tooltip strings--> <!--Tooltip strings-->
<message name="IDS_TOOLTIP_BACK" desc="The tooltip for back button"> <message name="IDS_TOOLTIP_BACK" desc="The tooltip for back button">
......
12b98f99d75698c0a0ef26743f25c7dbd3457cd2
\ No newline at end of file
5f987e96bfd6c48895c012a4abdd40306e50e24d
\ No newline at end of file
...@@ -31,7 +31,9 @@ js_library("read_later_api_proxy") { ...@@ -31,7 +31,9 @@ js_library("read_later_api_proxy") {
js_library("read_later_item") { js_library("read_later_item") {
deps = [ deps = [
":read_later_api_proxy",
"//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
"//ui/webui/resources/cr_elements/cr_icon_button:cr_icon_button.m",
] ]
} }
......
...@@ -35,13 +35,11 @@ ...@@ -35,13 +35,11 @@
<div class="sub-heading">$i18n{unreadHeader}</div> <div class="sub-heading">$i18n{unreadHeader}</div>
<template id="ureadItemsList" is="dom-repeat" items="[[unreadItems_]]"> <template id="ureadItemsList" is="dom-repeat" items="[[unreadItems_]]">
<read-later-item data-url$="[[item.url]]" class="mwb-list-item" <read-later-item data-url$="[[item.url]]" class="mwb-list-item"
data="[[item]]" on-click="onItemClick_"> data="[[item]]"></read-later-item>
</read-later-item>
</template> </template>
<div class="sub-heading">$i18n{readHeader}</div> <div class="sub-heading">$i18n{readHeader}</div>
<template id="readItemsList" is="dom-repeat" items="[[readItems_]]"> <template id="readItemsList" is="dom-repeat" items="[[readItems_]]">
<read-later-item data-url$="[[item.url]]" class="mwb-list-item" <read-later-item data-url$="[[item.url]]" class="mwb-list-item"
data="[[item]]" on-click="onItemClick_"> data="[[item]]"></read-later-item>
</read-later-item>
</template> </template>
</div> </div>
...@@ -34,27 +34,40 @@ export class ReadLaterAppElement extends PolymerElement { ...@@ -34,27 +34,40 @@ export class ReadLaterAppElement extends PolymerElement {
super(); super();
/** @private {!ReadLaterApiProxy} */ /** @private {!ReadLaterApiProxy} */
this.apiProxy_ = ReadLaterApiProxyImpl.getInstance(); this.apiProxy_ = ReadLaterApiProxyImpl.getInstance();
/** @private {?number} */
this.listenerId_ = null;
} }
/** @override */ /** @override */
ready() { ready() {
super.ready(); super.ready();
this.updateItems_();
}
/** @override */
connectedCallback() {
super.connectedCallback();
const callbackRouter = this.apiProxy_.getCallbackRouter();
this.listenerId_ =
callbackRouter.itemsChanged.addListener(() => this.updateItems_());
}
/** @override */
disconnectedCallback() {
super.disconnectedCallback();
this.apiProxy_.getCallbackRouter().removeListener(
/** @type {number} */ (this.listenerId_));
this.listenerId_ = null;
}
/** @private */
updateItems_() {
this.apiProxy_.getReadLaterEntries().then(({entries}) => { this.apiProxy_.getReadLaterEntries().then(({entries}) => {
this.unreadItems_ = entries.unreadEntries; this.unreadItems_ = entries.unreadEntries;
this.readItems_ = entries.readEntries; this.readItems_ = entries.readEntries;
}); });
} }
/**
* @param {!Event} e
* @private
*/
onItemClick_(e) {
const item =
/** @type {!ReadLaterItemElement} */ (e.currentTarget);
this.apiProxy_.openSavedEntry(item.data.url);
}
} }
customElements.define(ReadLaterAppElement.is, ReadLaterAppElement); customElements.define(ReadLaterAppElement.is, ReadLaterAppElement);
...@@ -18,6 +18,18 @@ export class ReadLaterApiProxy { ...@@ -18,6 +18,18 @@ export class ReadLaterApiProxy {
/** @param {!url.mojom.Url} url */ /** @param {!url.mojom.Url} url */
openSavedEntry(url) {} openSavedEntry(url) {}
/**
* @param {!url.mojom.Url} url
* @param {boolean} read
*/
updateReadStatus(url, read) {}
/** @param {!url.mojom.Url} url */
removeEntry(url) {}
/** @return {!readLater.mojom.PageCallbackRouter} */
getCallbackRouter() {}
} }
/** @implements {ReadLaterApiProxy} */ /** @implements {ReadLaterApiProxy} */
...@@ -44,6 +56,21 @@ export class ReadLaterApiProxyImpl { ...@@ -44,6 +56,21 @@ export class ReadLaterApiProxyImpl {
openSavedEntry(url) { openSavedEntry(url) {
this.handler.openSavedEntry(url); this.handler.openSavedEntry(url);
} }
/** @override */
updateReadStatus(url, read) {
this.handler.updateReadStatus(url, read);
}
/** @override */
removeEntry(url) {
this.handler.removeEntry(url);
}
/** @override */
getCallbackRouter() {
return this.callbackRouter;
}
} }
addSingletonGetter(ReadLaterApiProxyImpl); addSingletonGetter(ReadLaterApiProxyImpl);
<style> <style>
:host(:hover) .button-container,
:host(.selected) .button-container {
display: flex;
}
.button-container {
display: none;
}
.text-container { .text-container {
flex-grow: 1; flex-grow: 1;
overflow: hidden; overflow: hidden;
...@@ -22,6 +31,12 @@ ...@@ -22,6 +31,12 @@
color: var(--cr-secondary-text-color); color: var(--cr-secondary-text-color);
font-size: var(--mwb-secondary-text-font-size); font-size: var(--mwb-secondary-text-font-size);
} }
cr-icon-button {
--cr-icon-button-margin-end: calc(var(--mwb-icon-size) / 4);
--cr-icon-button-margin-start: calc(var(--mwb-icon-size) / 4);
--cr-icon-button-size: var(--mwb-icon-size);
}
</style> </style>
<div class="text-container"> <div class="text-container">
...@@ -30,3 +45,16 @@ ...@@ -30,3 +45,16 @@
[[data.displayUrl]] - [[data.displayTimeSinceUpdate]] [[data.displayUrl]] - [[data.displayTimeSinceUpdate]]
</div> </div>
</div> </div>
<div class="button-container">
<cr-icon-button id="updateStatusButton"
aria-label="[[getUpdateStatusButtonTooltip_(
'$i18n{tooltipMarkAsUnread}', '$i18n{tooltipMarkAsRead}', data.read)]]"
iron-icon="cr:check" title="[[getUpdateStatusButtonTooltip_(
'$i18n{tooltipMarkAsUnread}', '$i18n{tooltipMarkAsRead}', data.read)]]"
on-click="onUpdateStatusClick_">
</cr-icon-button>
<cr-icon-button id="deleteButton" aria-label="$i18n{tooltipDelete}"
iron-icon="cr:close" title="$i18n{tooltipDelete}"
on-click="onItemDeleteClick_">
</cr-icon-button>
</div>
...@@ -2,11 +2,16 @@ ...@@ -2,11 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js';
import 'chrome://resources/cr_elements/cr_icons_css.m.js';
import 'chrome://resources/cr_elements/icons.m.js';
import 'chrome://resources/cr_elements/mwb_shared_vars.js'; import 'chrome://resources/cr_elements/mwb_shared_vars.js';
import 'chrome://resources/cr_elements/shared_vars_css.m.js'; import 'chrome://resources/cr_elements/shared_vars_css.m.js';
import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {ReadLaterApiProxy, ReadLaterApiProxyImpl} from './read_later_api_proxy.js';
export class ReadLaterItemElement extends PolymerElement { export class ReadLaterItemElement extends PolymerElement {
static get is() { static get is() {
return 'read-later-item'; return 'read-later-item';
...@@ -22,6 +27,51 @@ export class ReadLaterItemElement extends PolymerElement { ...@@ -22,6 +27,51 @@ export class ReadLaterItemElement extends PolymerElement {
data: Object, data: Object,
}; };
} }
constructor() {
super();
/** @private {!ReadLaterApiProxy} */
this.apiProxy_ = ReadLaterApiProxyImpl.getInstance();
}
/** @override */
ready() {
super.ready();
this.addEventListener('click', this.onClick_);
}
/** @private */
onClick_() {
this.apiProxy_.openSavedEntry(this.data.url);
}
/**
* @param {!Event} e
* @private
*/
onUpdateStatusClick_(e) {
e.stopPropagation();
this.apiProxy_.updateReadStatus(this.data.url, !this.data.read);
}
/**
* @param {!Event} e
* @private
*/
onItemDeleteClick_(e) {
e.stopPropagation();
this.apiProxy_.removeEntry(this.data.url);
}
/**
* @param {string} markAsUnreadTooltip
* @param {string} markAsReadTooltip
* @return {string} The appropriate tooltip for the current state
* @private
*/
getUpdateStatusButtonTooltip_(markAsUnreadTooltip, markAsReadTooltip) {
return this.data.read ? markAsUnreadTooltip : markAsReadTooltip;
}
} }
customElements.define(ReadLaterItemElement.is, ReadLaterItemElement); customElements.define(ReadLaterItemElement.is, ReadLaterItemElement);
...@@ -18,6 +18,8 @@ struct ReadLaterEntry { ...@@ -18,6 +18,8 @@ struct ReadLaterEntry {
url.mojom.Url url; url.mojom.Url url;
string display_url; string display_url;
int64 update_time; int64 update_time;
// Whether the entry has been read.
bool read;
string display_time_since_update; string display_time_since_update;
}; };
...@@ -45,4 +47,7 @@ interface PageHandler { ...@@ -45,4 +47,7 @@ interface PageHandler {
// WebUI-side handler for requests from the browser. // WebUI-side handler for requests from the browser.
interface Page { interface Page {
// Callback when any item in read later is
// changed/removed.
ItemsChanged();
}; };
...@@ -85,10 +85,12 @@ void ReadLaterPageHandler::OpenSavedEntry(const GURL& url) { ...@@ -85,10 +85,12 @@ void ReadLaterPageHandler::OpenSavedEntry(const GURL& url) {
void ReadLaterPageHandler::UpdateReadStatus(const GURL& url, bool read) { void ReadLaterPageHandler::UpdateReadStatus(const GURL& url, bool read) {
reading_list_model_->SetReadStatus(url, read); reading_list_model_->SetReadStatus(url, read);
page_->ItemsChanged();
} }
void ReadLaterPageHandler::RemoveEntry(const GURL& url) { void ReadLaterPageHandler::RemoveEntry(const GURL& url) {
reading_list_model_->RemoveEntryByURL(url); reading_list_model_->RemoveEntryByURL(url);
page_->ItemsChanged();
} }
read_later::mojom::ReadLaterEntryPtr ReadLaterPageHandler::GetEntryData( read_later::mojom::ReadLaterEntryPtr ReadLaterPageHandler::GetEntryData(
...@@ -105,6 +107,7 @@ read_later::mojom::ReadLaterEntryPtr ReadLaterPageHandler::GetEntryData( ...@@ -105,6 +107,7 @@ read_later::mojom::ReadLaterEntryPtr ReadLaterPageHandler::GetEntryData(
url_formatter::kFormatUrlTrimAfterHost, url_formatter::kFormatUrlTrimAfterHost,
net::UnescapeRule::NORMAL, nullptr, nullptr, nullptr)); net::UnescapeRule::NORMAL, nullptr, nullptr, nullptr));
entry_data->update_time = entry->UpdateTime(); entry_data->update_time = entry->UpdateTime();
entry_data->read = entry->IsRead();
entry_data->display_time_since_update = entry_data->display_time_since_update =
GetTimeSinceLastUpdate(entry->UpdateTime()); GetTimeSinceLastUpdate(entry->UpdateTime());
......
...@@ -42,6 +42,8 @@ class MockPage : public read_later::mojom::Page { ...@@ -42,6 +42,8 @@ class MockPage : public read_later::mojom::Page {
return receiver_.BindNewPipeAndPassRemote(); return receiver_.BindNewPipeAndPassRemote();
} }
mojo::Receiver<read_later::mojom::Page> receiver_{this}; mojo::Receiver<read_later::mojom::Page> receiver_{this};
MOCK_METHOD0(ItemsChanged, void());
}; };
void ExpectNewReadLaterEntry(const read_later::mojom::ReadLaterEntry* entry, void ExpectNewReadLaterEntry(const read_later::mojom::ReadLaterEntry* entry,
...@@ -104,8 +106,9 @@ class TestReadLaterPageHandlerTest : public BrowserWithTestWindowTest { ...@@ -104,8 +106,9 @@ class TestReadLaterPageHandlerTest : public BrowserWithTestWindowTest {
base::ASCIIToUTF16(title)); base::ASCIIToUTF16(title));
} }
private:
testing::StrictMock<MockPage> page_; testing::StrictMock<MockPage> page_;
private:
std::unique_ptr<TestReadLaterPageHandler> handler_; std::unique_ptr<TestReadLaterPageHandler> handler_;
ReadingListModel* model_; ReadingListModel* model_;
}; };
...@@ -156,6 +159,7 @@ TEST_F(TestReadLaterPageHandlerTest, OpenSavedEntry) { ...@@ -156,6 +159,7 @@ TEST_F(TestReadLaterPageHandlerTest, OpenSavedEntry) {
TEST_F(TestReadLaterPageHandlerTest, UpdateReadStatus) { TEST_F(TestReadLaterPageHandlerTest, UpdateReadStatus) {
handler()->UpdateReadStatus(GURL(kTabUrl3), true); handler()->UpdateReadStatus(GURL(kTabUrl3), true);
EXPECT_CALL(page_, ItemsChanged()).Times(1);
// Get Read later entries. // Get Read later entries.
read_later::mojom::PageHandler::GetReadLaterEntriesCallback callback1 = read_later::mojom::PageHandler::GetReadLaterEntriesCallback callback1 =
...@@ -177,6 +181,7 @@ TEST_F(TestReadLaterPageHandlerTest, UpdateReadStatus) { ...@@ -177,6 +181,7 @@ TEST_F(TestReadLaterPageHandlerTest, UpdateReadStatus) {
TEST_F(TestReadLaterPageHandlerTest, RemoveEntry) { TEST_F(TestReadLaterPageHandlerTest, RemoveEntry) {
handler()->RemoveEntry(GURL(kTabUrl3)); handler()->RemoveEntry(GURL(kTabUrl3));
EXPECT_CALL(page_, ItemsChanged()).Times(1);
// Get Read later entries. // Get Read later entries.
read_later::mojom::PageHandler::GetReadLaterEntriesCallback callback1 = read_later::mojom::PageHandler::GetReadLaterEntriesCallback callback1 =
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "chrome/browser/ui/webui/read_later/read_later_ui.h" #include "chrome/browser/ui/webui/read_later/read_later_ui.h"
#include <string>
#include <utility> #include <utility>
#include "chrome/browser/ui/webui/read_later/read_later_page_handler.h" #include "chrome/browser/ui/webui/read_later/read_later_page_handler.h"
...@@ -16,12 +17,21 @@ ...@@ -16,12 +17,21 @@
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h" #include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_data_source.h" #include "content/public/browser/web_ui_data_source.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/webui/web_ui_util.h" #include "ui/base/webui/web_ui_util.h"
namespace { namespace {
constexpr char kGeneratedPath[] = constexpr char kGeneratedPath[] =
"@out_folder@/gen/chrome/browser/resources/read_later/"; "@out_folder@/gen/chrome/browser/resources/read_later/";
void AddLocalizedString(content::WebUIDataSource* source,
const std::string& message,
int id) {
base::string16 str = l10n_util::GetStringUTF16(id);
base::Erase(str, '&');
source->AddString(message, str);
} }
} // namespace
ReadLaterUI::ReadLaterUI(content::WebUI* web_ui) ReadLaterUI::ReadLaterUI(content::WebUI* web_ui)
: ui::MojoWebUIController(web_ui) { : ui::MojoWebUIController(web_ui) {
...@@ -30,11 +40,16 @@ ReadLaterUI::ReadLaterUI(content::WebUI* web_ui) ...@@ -30,11 +40,16 @@ ReadLaterUI::ReadLaterUI(content::WebUI* web_ui)
source->AddResourcePath("read_later.mojom-lite.js", source->AddResourcePath("read_later.mojom-lite.js",
IDR_READ_LATER_MOJO_LITE_JS); IDR_READ_LATER_MOJO_LITE_JS);
static constexpr webui::LocalizedString kLocalizedStrings[] = { static constexpr webui::LocalizedString kLocalizedStrings[] = {
{"readHeader", IDS_READ_LATER_MENU_READ_HEADER},
{"title", IDS_READ_LATER_MENU_TITLE}, {"title", IDS_READ_LATER_MENU_TITLE},
{"tooltipDelete", IDS_DELETE},
{"tooltipMarkAsRead", IDS_READ_LATER_MENU_TOOLTIP_MARK_AS_READ},
{"tooltipMarkAsUnread", IDS_READ_LATER_MENU_TOOLTIP_MARK_AS_UNREAD},
{"unreadHeader", IDS_READ_LATER_MENU_UNREAD_HEADER}, {"unreadHeader", IDS_READ_LATER_MENU_UNREAD_HEADER},
{"readHeader", IDS_READ_LATER_MENU_READ_HEADER},
}; };
AddLocalizedStringsBulk(source, kLocalizedStrings); for (const auto& str : kLocalizedStrings)
AddLocalizedString(source, str.name, str.id);
webui::SetupWebUIDataSource( webui::SetupWebUIDataSource(
source, base::make_span(kReadLaterResources, kReadLaterResourcesSize), source, base::make_span(kReadLaterResources, kReadLaterResourcesSize),
kGeneratedPath, IDR_READ_LATER_HTML); kGeneratedPath, IDR_READ_LATER_HTML);
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
import {ReadLaterAppElement} from 'chrome://read-later/app.js'; import {ReadLaterAppElement} from 'chrome://read-later/app.js';
import {ReadLaterApiProxy, ReadLaterApiProxyImpl} from 'chrome://read-later/read_later_api_proxy.js'; import {ReadLaterApiProxy, ReadLaterApiProxyImpl} from 'chrome://read-later/read_later_api_proxy.js';
import {assertEquals} from '../chai_assert.js'; import {assertEquals, assertFalse, assertTrue} from '../chai_assert.js';
import {flushTasks} from '../test_util.m.js'; import {flushTasks} from '../test_util.m.js';
import {TestReadLaterApiProxy} from './test_read_later_api_proxy.js'; import {TestReadLaterApiProxy} from './test_read_later_api_proxy.js';
...@@ -46,6 +46,7 @@ suite('ReadLaterAppTest', () => { ...@@ -46,6 +46,7 @@ suite('ReadLaterAppTest', () => {
url: 'https://www.google.com', url: 'https://www.google.com',
displayUrl: 'google.com', displayUrl: 'google.com',
updateTime: 0, updateTime: 0,
read: false,
displayTimeSinceUpdate: '2 minutes ago', displayTimeSinceUpdate: '2 minutes ago',
}, },
{ {
...@@ -53,6 +54,7 @@ suite('ReadLaterAppTest', () => { ...@@ -53,6 +54,7 @@ suite('ReadLaterAppTest', () => {
url: 'https://www.apple.com', url: 'https://www.apple.com',
displayUrl: 'apple.com', displayUrl: 'apple.com',
updateTime: 0, updateTime: 0,
read: false,
displayTimeSinceUpdate: '20 minutes ago', displayTimeSinceUpdate: '20 minutes ago',
}, },
], ],
...@@ -62,6 +64,7 @@ suite('ReadLaterAppTest', () => { ...@@ -62,6 +64,7 @@ suite('ReadLaterAppTest', () => {
url: 'https://www.bing.com', url: 'https://www.bing.com',
displayUrl: 'bing.com', displayUrl: 'bing.com',
updateTime: 0, updateTime: 0,
read: true,
displayTimeSinceUpdate: '5 minutes ago', displayTimeSinceUpdate: '5 minutes ago',
}, },
{ {
...@@ -69,6 +72,7 @@ suite('ReadLaterAppTest', () => { ...@@ -69,6 +72,7 @@ suite('ReadLaterAppTest', () => {
url: 'https://www.yahoo.com', url: 'https://www.yahoo.com',
displayUrl: 'yahoo.com', displayUrl: 'yahoo.com',
updateTime: 0, updateTime: 0,
read: true,
displayTimeSinceUpdate: '7 minutes ago', displayTimeSinceUpdate: '7 minutes ago',
}, },
] ]
...@@ -97,10 +101,48 @@ suite('ReadLaterAppTest', () => { ...@@ -97,10 +101,48 @@ suite('ReadLaterAppTest', () => {
assertEntryURLs(queryItems(), urls); assertEntryURLs(queryItems(), urls);
}); });
test('click passes correct url', async () => { test('click on item passes correct url', async () => {
const expectedUrl = 'https://www.apple.com'; const expectedUrl = 'https://www.apple.com';
clickItem(expectedUrl); clickItem(expectedUrl);
const url = await testProxy.whenCalled('openSavedEntry'); const url = await testProxy.whenCalled('openSavedEntry');
assertEquals(url, expectedUrl); assertEquals(url, expectedUrl);
}); });
test('Click on item mark as read button triggers actions', async () => {
const expectedUrl = 'https://www.apple.com';
const readLaterItem =
readLaterApp.shadowRoot.querySelector(`[data-url="${expectedUrl}"]`);
const readLaterItemUpdateStatusButton =
readLaterItem.shadowRoot.querySelector('#updateStatusButton');
readLaterItemUpdateStatusButton.click();
const [url, read] = await testProxy.whenCalled('updateReadStatus');
assertEquals(expectedUrl, url);
assertTrue(read);
});
test('Click on item mark as unread button triggers actions', async () => {
const expectedUrl = 'https://www.bing.com';
const readLaterItem =
readLaterApp.shadowRoot.querySelector(`[data-url="${expectedUrl}"]`);
const readLaterItemUpdateStatusButton =
readLaterItem.shadowRoot.querySelector('#updateStatusButton');
readLaterItemUpdateStatusButton.click();
const [url, read] = await testProxy.whenCalled('updateReadStatus');
assertEquals(expectedUrl, url);
assertFalse(read);
});
test('Click on item delete button triggers actions', async () => {
const expectedUrl = 'https://www.apple.com';
const readLaterItem =
readLaterApp.shadowRoot.querySelector(`[data-url="${expectedUrl}"]`);
const readLaterItemDeleteButton =
readLaterItem.shadowRoot.querySelector('#deleteButton');
readLaterItemDeleteButton.click();
const url = await testProxy.whenCalled('removeEntry');
assertEquals(expectedUrl, url);
});
}); });
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'chrome://read-later/read_later.mojom-lite.js';
import {ReadLaterApiProxy} from 'chrome://read-later/read_later_api_proxy.js'; import {ReadLaterApiProxy} from 'chrome://read-later/read_later_api_proxy.js';
import {TestBrowserProxy} from '../test_browser_proxy.m.js'; import {TestBrowserProxy} from '../test_browser_proxy.m.js';
...@@ -11,8 +13,13 @@ export class TestReadLaterApiProxy extends TestBrowserProxy { ...@@ -11,8 +13,13 @@ export class TestReadLaterApiProxy extends TestBrowserProxy {
super([ super([
'getReadLaterEntries', 'getReadLaterEntries',
'openSavedEntry', 'openSavedEntry',
'updateReadStatus',
'removeEntry',
]); ]);
/** @type {!readLater.mojom.PageCallbackRouter} */
this.callbackRouter = new readLater.mojom.PageCallbackRouter();
/** @private {!readLater.mojom.ReadLaterEntriesByStatus} */ /** @private {!readLater.mojom.ReadLaterEntriesByStatus} */
this.entries_; this.entries_;
} }
...@@ -28,6 +35,21 @@ export class TestReadLaterApiProxy extends TestBrowserProxy { ...@@ -28,6 +35,21 @@ export class TestReadLaterApiProxy extends TestBrowserProxy {
this.methodCalled('openSavedEntry', url); this.methodCalled('openSavedEntry', url);
} }
/** @override */
updateReadStatus(url, read) {
this.methodCalled('updateReadStatus', [url, read]);
}
/** @override */
removeEntry(url) {
this.methodCalled('removeEntry', url);
}
/** @override */
getCallbackRouter() {
return this.callbackRouter;
}
/** @param {!readLater.mojom.ReadLaterEntriesByStatus} entries */ /** @param {!readLater.mojom.ReadLaterEntriesByStatus} entries */
setEntries(entries) { setEntries(entries) {
this.entries_ = entries; this.entries_ = entries;
......
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