diff --git a/packages/data-context/src/actions/ElectronActions.ts b/packages/data-context/src/actions/ElectronActions.ts index afce5ab557ad..091e81d54677 100644 --- a/packages/data-context/src/actions/ElectronActions.ts +++ b/packages/data-context/src/actions/ElectronActions.ts @@ -1,4 +1,4 @@ -import type { App, BrowserWindow, OpenDialogOptions, OpenDialogReturnValue, SaveDialogOptions, SaveDialogReturnValue } from 'electron' +import type { App, BrowserWindow, OpenDialogOptions, OpenDialogReturnValue, SaveDialogOptions, SaveDialogReturnValue, Notification } from 'electron' import os from 'os' import type { DataContext } from '..' import _ from 'lodash' @@ -13,6 +13,7 @@ export interface ElectronApiShape { copyTextToClipboard(text: string): void isMainWindowFocused(): boolean focusMainWindow(): void + createNotification(title: string, body: string): Notification } export class ElectronActions { @@ -104,4 +105,18 @@ export class ElectronActions { return obj.filePath || null }) } + + showSystemNotification (title: string, body: string, onClick?: () => void) { + const notification = this.ctx.electronApi.createNotification(title, body) + + const defaultOnClick = async () => { + await this.ctx.actions.browser.focusActiveBrowserWindow() + } + + const clickHandler = onClick || defaultOnClick + + notification.on('click', clickHandler) + + notification.show() + } } diff --git a/packages/graphql/schemas/schema.graphql b/packages/graphql/schemas/schema.graphql index 572d6ada5b25..051f97132614 100644 --- a/packages/graphql/schemas/schema.graphql +++ b/packages/graphql/schemas/schema.graphql @@ -1786,6 +1786,9 @@ type Mutation { """Set failed tests for the current run to be used by the runner""" setTestsForRun(testsBySpec: [TestsBySpecInput!]!): Boolean + """Show system notification via Electron""" + showSystemNotification(body: String!, title: String!): Boolean + """Switch Testing type and relaunch browser""" switchTestingTypeAndRelaunch(testingType: TestingTypeEnum!): Boolean diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-Mutation.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-Mutation.ts index 3e7f04e8121f..c29d019bc02e 100644 --- a/packages/graphql/src/schemaTypes/objectTypes/gql-Mutation.ts +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-Mutation.ts @@ -775,6 +775,19 @@ export const mutation = mutationType({ }, }) + t.boolean('showSystemNotification', { + description: 'Show system notification via Electron', + args: { + title: nonNull(stringArg()), + body: nonNull(stringArg()), + }, + resolve: async (source, args, ctx) => { + ctx.actions.electron.showSystemNotification(args.title, args.body) + + return true + }, + }) + t.boolean('moveToRelevantRun', { description: 'Allow the relevant run for debugging marked as next to be considered the current relevant run', args: { @@ -787,7 +800,7 @@ export const mutation = mutationType({ }, }) - //Using a mutation to just return data in order to be able to await the results in the component + // Using a mutation to just return data in order to be able to await the results in the component t.list.nonNull.string('testsForRun', { description: 'Return the set of test titles for the given spec path', args: { diff --git a/packages/server/lib/makeDataContext.ts b/packages/server/lib/makeDataContext.ts index a3cab7acf137..74b7349df09c 100644 --- a/packages/server/lib/makeDataContext.ts +++ b/packages/server/lib/makeDataContext.ts @@ -189,6 +189,9 @@ export function makeDataContext (options: MakeDataContextOptions): DataContext { focusMainWindow () { return focusMainWindow() }, + createNotification (title, body) { + return new electron.Notification({ title, body }) + }, }, localSettingsApi: { async setPreferences (object: AllowedState) { diff --git a/packages/server/lib/modes/interactive.ts b/packages/server/lib/modes/interactive.ts index fe7227cf6369..b76912ca5dd3 100644 --- a/packages/server/lib/modes/interactive.ts +++ b/packages/server/lib/modes/interactive.ts @@ -157,6 +157,11 @@ export = { }, async run (options: LaunchArgs, _loading: Promise) { + // Need to set this for system notifications to appear as "Cypress" on Windows + if (app.setAppUserModelId) { + app.setAppUserModelId('Cypress') + } + // Note: We do not await the `_loading` promise here since initializing // the data context can significantly delay initial render of the UI // https://github.com/cypress-io/cypress/issues/26388#issuecomment-1492616609