Skip to content
Permalink
Browse files
notification.close() not working
https://bugs.webkit.org/show_bug.cgi?id=248309
rdar://problem/102683841

Reviewed by Chris Dumez.

Make sure to mark the notifications as showing so that close actually does something.
Covered by API test.

* Source/WebCore/workers/service/ServiceWorkerContainer.cpp:
(WebCore::ServiceWorkerContainer::getNotifications):
* Tools/TestWebKitAPI/TestNotificationProvider.cpp:
(TestWebKitAPI::closeWebNotification):
(TestWebKitAPI::TestNotificationProvider::TestNotificationProvider):
(TestWebKitAPI::TestNotificationProvider::showWebNotification):
(TestWebKitAPI::TestNotificationProvider::closeWebNotification):
(TestWebKitAPI::TestNotificationProvider::resetHasReceivedNotification):
* Tools/TestWebKitAPI/TestNotificationProvider.h:
(TestWebKitAPI::TestNotificationProvider::hasReceivedShowNotification const):
(TestWebKitAPI::TestNotificationProvider::hasReceivedCloseNotification const):
(TestWebKitAPI::TestNotificationProvider::hasReceivedNotification const): Deleted.
(TestWebKitAPI::TestNotificationProvider::resetHasReceivedNotification): Deleted.
* Tools/TestWebKitAPI/Tests/WebKitCocoa/PushAPI.mm:

Canonical link: https://commits.webkit.org/257108@main
  • Loading branch information
youennf committed Nov 29, 2022
1 parent 7543702 commit d02120f1bc06da2453a9fa69884a4dd2b4733643
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 8 deletions.
@@ -636,7 +636,9 @@ void ServiceWorkerContainer::getNotifications(const URL& serviceWorkerRegistrati

auto data = result.releaseReturnValue();
auto notifications = map(data, [context](auto&& data) {
return Notification::create(*context, WTFMove(data));
auto notification = Notification::create(*context, WTFMove(data));
notification->markAsShown();
return notification;
});
promise.resolve(WTFMove(notifications));
});
@@ -44,6 +44,11 @@ static void showWebNotification(WKPageRef page, WKNotificationRef notification,
static_cast<TestNotificationProvider*>(const_cast<void*>(clientInfo))->showWebNotification(page, notification);
}

static void closeWebNotification(WKNotificationRef notification, const void* clientInfo)
{
static_cast<TestNotificationProvider*>(const_cast<void*>(clientInfo))->closeWebNotification(notification);
}

static WKDictionaryRef notificationPermissions(const void* clientInfo)
{
return static_cast<TestNotificationProvider*>(const_cast<void*>(clientInfo))->notificationPermissions();
@@ -53,9 +58,9 @@ TestNotificationProvider::TestNotificationProvider(Vector<WKNotificationManagerR
: m_managers(WTFMove(managers))
{
m_provider = {
{ 0, this },
WKNotificationProviderBase { 0, this },
&TestWebKitAPI::showWebNotification,
0, // closeWebNotification
&TestWebKitAPI::closeWebNotification,
0, // didDestroyNotification
0, // addNotificationManager
0, // removeNotificationManager
@@ -120,7 +125,7 @@ static WKNotificationManagerRef notificationManagerForPage(WKPageRef page)

void TestNotificationProvider::showWebNotification(WKPageRef page, WKNotificationRef notification)
{
m_hasReceivedNotification = true;
m_hasReceivedShowNotification = true;

auto notificationManager = notificationManagerForPage(page);
uint64_t identifier = WKNotificationGetID(notification);
@@ -130,6 +135,18 @@ void TestNotificationProvider::showWebNotification(WKPageRef page, WKNotificatio
m_pendingNotification = std::make_pair(notificationManager, identifier);
}

void TestNotificationProvider::closeWebNotification(WKNotificationRef notification)
{
ASSERT(!m_hasReceivedCloseNotification);
m_hasReceivedCloseNotification = true;
}

void TestNotificationProvider::resetHasReceivedNotification()
{
m_hasReceivedShowNotification = false;
m_hasReceivedCloseNotification = false;
}

bool TestNotificationProvider::simulateNotificationClick()
{
if (!m_pendingNotification.first)
@@ -45,17 +45,20 @@ class TestNotificationProvider {

WKDictionaryRef notificationPermissions() const;
void showWebNotification(WKPageRef, WKNotificationRef);
void closeWebNotification(WKNotificationRef);
bool simulateNotificationClick();

bool hasReceivedNotification() const { return m_hasReceivedNotification; }
void resetHasReceivedNotification() { m_hasReceivedNotification = false; }
bool hasReceivedShowNotification() const { return m_hasReceivedShowNotification; }
bool hasReceivedCloseNotification() const { return m_hasReceivedCloseNotification; }
void resetHasReceivedNotification();

private:
Vector<WKNotificationManagerRef> m_managers;
HashMap<String, bool> m_permissions;
WKNotificationProviderV0 m_provider;

bool m_hasReceivedNotification { false };
bool m_hasReceivedShowNotification { false };
bool m_hasReceivedCloseNotification { false };
std::pair<WKNotificationManagerRef, uint64_t> m_pendingNotification;
};

@@ -707,7 +707,7 @@ function log(msg)
expectedMessage = "Received: Sweet Potatoes"_s;

[[configuration websiteDataStore] _processPushMessage:messageDictionary([message dataUsingEncoding:NSUTF8StringEncoding], [server.request() URL]) completionHandler:^(bool result) {
EXPECT_TRUE(providerRef.hasReceivedNotification());
EXPECT_TRUE(providerRef.hasReceivedShowNotification());
pushMessageSuccessful = result;
pushMessageProcessed = true;
}];
@@ -727,6 +727,130 @@ function log(msg)
clearWebsiteDataStore([configuration websiteDataStore]);
}

static constexpr auto closeNotificationMainBytes = R"SWRESOURCE(
<script>
function log(msg)
{
window.webkit.messageHandlers.sw.postMessage(msg);
}
const channel = new MessageChannel();
channel.port1.onmessage = (event) => log(event.data);
navigator.serviceWorker.onmessage = (event) => log(event.data);
let swRegistration;
navigator.serviceWorker.register('/sw.js').then((registration) => {
swRegistration = registration;
if (registration.active) {
registration.active.postMessage({port: channel.port2}, [channel.port2]);
return;
}
worker = registration.installing;
worker.addEventListener('statechange', function() {
if (worker.state == 'activated')
worker.postMessage({port: channel.port2}, [channel.port2]);
});
}).catch(function(error) {
log("Registration failed with: " + error);
});
function closeNotification()
{
const notifications = swRegistration.getNotifications().then(notifications => {
notifications[0].close();
log("PASS close notification");
});
}
</script>
)SWRESOURCE"_s;

static constexpr auto closeNotificationScriptBytes = R"SWRESOURCE(
let port;
self.addEventListener("message", (event) => {
if (port)
return;
port = event.data.port;
port.postMessage("Ready");
});
self.addEventListener("push", (event) => {
self.registration.showNotification("notification");
try {
if (!event.data) {
port.postMessage("Received: null data");
return;
}
const value = event.data.text();
port.postMessage("Received: " + value);
} catch (e) {
port.postMessage("Got exception " + e);
}
});
)SWRESOURCE"_s;

TEST(PushAPI, fireNotificationCloseEvent)
{
TestWebKitAPI::HTTPServer server({
{ "/"_s, { closeNotificationMainBytes } },
{ "/sw.js"_s, { {{ "Content-Type"_s, "application/javascript"_s }}, closeNotificationScriptBytes } }
}, TestWebKitAPI::HTTPServer::Protocol::Http);

[WKWebsiteDataStore _allowWebsiteDataRecordsForAllOrigins];

auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);

auto provider = TestWebKitAPI::TestNotificationProvider({ [[configuration processPool] _notificationManagerForTesting], WKNotificationManagerGetSharedServiceWorkerNotificationManager() });
provider.setPermission(server.origin(), true);

auto messageHandler = adoptNS([[PushAPIMessageHandlerWithExpectedMessage alloc] init]);
[[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"sw"];

clearWebsiteDataStore([configuration websiteDataStore]);

expectedMessage = "Ready"_s;
auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
[webView loadRequest:server.request()];

TestWebKitAPI::Util::run(&done);

provider.resetHasReceivedNotification();
auto& providerRef = provider;

done = false;
pushMessageProcessed = false;
pushMessageSuccessful = false;
NSString *message = @"Sweet Potatoes";
expectedMessage = "Received: Sweet Potatoes"_s;

[[configuration websiteDataStore] _processPushMessage:messageDictionary([message dataUsingEncoding:NSUTF8StringEncoding], [server.request() URL]) completionHandler:^(bool result) {
EXPECT_TRUE(providerRef.hasReceivedShowNotification());
pushMessageSuccessful = result;
pushMessageProcessed = true;
}];
TestWebKitAPI::Util::run(&done);

TestWebKitAPI::Util::run(&pushMessageProcessed);
EXPECT_TRUE(pushMessageSuccessful);

terminateNetworkProcessWhileRegistrationIsStored(configuration.get());

[webView evaluateJavaScript:@"closeNotification()" completionHandler:nil];

EXPECT_FALSE(providerRef.hasReceivedCloseNotification());

done = false;
expectedMessage = "PASS close notification"_s;
TestWebKitAPI::Util::run(&done);

int counter = 0;
while (!providerRef.hasReceivedCloseNotification() && ++counter < 10)
TestWebKitAPI::Util::spinRunLoop(10);

EXPECT_LT(counter, 10);

providerRef.resetHasReceivedNotification();

clearWebsiteDataStore([configuration websiteDataStore]);
}
#endif // WK_HAVE_C_SPI

#endif // ENABLE(NOTIFICATIONS) && ENABLE(NOTIFICATION_EVENT)

0 comments on commit d02120f

Please sign in to comment.