api-notification-dbus-spec.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // For these tests we use a fake DBus daemon to verify libnotify interaction
  2. // with the session bus. This requires python-dbusmock to be installed and
  3. // running at $DBUS_SESSION_BUS_ADDRESS.
  4. //
  5. // script/spec-runner.js spawns dbusmock, which sets DBUS_SESSION_BUS_ADDRESS.
  6. //
  7. // See https://pypi.python.org/pypi/python-dbusmock to read about dbusmock.
  8. import { expect } from 'chai';
  9. import * as dbus from 'dbus-native';
  10. import { app } from 'electron/main';
  11. import { ifdescribe } from './lib/spec-helpers';
  12. import { promisify } from 'node:util';
  13. const skip = process.platform !== 'linux' ||
  14. process.arch === 'ia32' ||
  15. process.arch.indexOf('arm') === 0 ||
  16. !process.env.DBUS_SESSION_BUS_ADDRESS;
  17. ifdescribe(!skip)('Notification module (dbus)', () => {
  18. let mock: any, Notification, getCalls: any, reset: any;
  19. const realAppName = app.name;
  20. const realAppVersion = app.getVersion();
  21. const appName = 'api-notification-dbus-spec';
  22. const serviceName = 'org.freedesktop.Notifications';
  23. before(async () => {
  24. // init app
  25. app.name = appName;
  26. app.setDesktopName(`${appName}.desktop`);
  27. // init DBus
  28. const path = '/org/freedesktop/Notifications';
  29. const iface = 'org.freedesktop.DBus.Mock';
  30. console.log(`session bus: ${process.env.DBUS_SESSION_BUS_ADDRESS}`);
  31. const bus = dbus.sessionBus();
  32. const service = bus.getService(serviceName);
  33. const getInterface = promisify(service.getInterface.bind(service));
  34. mock = await getInterface(path, iface);
  35. getCalls = promisify(mock.GetCalls.bind(mock));
  36. reset = promisify(mock.Reset.bind(mock));
  37. });
  38. after(async () => {
  39. // cleanup dbus
  40. if (reset) await reset();
  41. // cleanup app
  42. app.setName(realAppName);
  43. app.setVersion(realAppVersion);
  44. });
  45. describe(`Notification module using ${serviceName}`, () => {
  46. function onMethodCalled (done: () => void) {
  47. function cb (name: string) {
  48. console.log(`onMethodCalled: ${name}`);
  49. if (name === 'Notify') {
  50. mock.removeListener('MethodCalled', cb);
  51. console.log('done');
  52. done();
  53. }
  54. }
  55. return cb;
  56. }
  57. function unmarshalDBusNotifyHints (dbusHints: any) {
  58. const o: Record<string, any> = {};
  59. for (const hint of dbusHints) {
  60. const key = hint[0];
  61. const value = hint[1][1][0];
  62. o[key] = value;
  63. }
  64. return o;
  65. }
  66. function unmarshalDBusNotifyArgs (dbusArgs: any) {
  67. return {
  68. app_name: dbusArgs[0][1][0],
  69. replaces_id: dbusArgs[1][1][0],
  70. app_icon: dbusArgs[2][1][0],
  71. title: dbusArgs[3][1][0],
  72. body: dbusArgs[4][1][0],
  73. actions: dbusArgs[5][1][0],
  74. hints: unmarshalDBusNotifyHints(dbusArgs[6][1][0])
  75. };
  76. }
  77. before(done => {
  78. mock.on('MethodCalled', onMethodCalled(done));
  79. // lazy load Notification after we listen to MethodCalled mock signal
  80. Notification = require('electron').Notification;
  81. const n = new Notification({
  82. title: 'title',
  83. subtitle: 'subtitle',
  84. body: 'body',
  85. replyPlaceholder: 'replyPlaceholder',
  86. sound: 'sound',
  87. closeButtonText: 'closeButtonText'
  88. });
  89. n.show();
  90. });
  91. it(`should call ${serviceName} to show notifications`, async () => {
  92. const calls = await getCalls();
  93. expect(calls).to.be.an('array').of.lengthOf.at.least(1);
  94. const lastCall = calls[calls.length - 1];
  95. const methodName = lastCall[1];
  96. expect(methodName).to.equal('Notify');
  97. const args = unmarshalDBusNotifyArgs(lastCall[2]);
  98. expect(args).to.deep.equal({
  99. app_name: appName,
  100. replaces_id: 0,
  101. app_icon: '',
  102. title: 'title',
  103. body: 'body',
  104. actions: [],
  105. hints: {
  106. append: 'true',
  107. 'desktop-entry': appName,
  108. urgency: 1
  109. }
  110. });
  111. });
  112. });
  113. });