Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add Pushpad provider for web push notifications #4235

Merged
merged 17 commits into from Oct 25, 2023

Conversation

collimarco
Copy link
Contributor

What change does this PR introduce?

Add Pushpad provider for web push notifications.

Why was this change needed?

Closes #4218

@collimarco
Copy link
Contributor Author

@parveshsaini @BiswaViraj @scopsy

Can you please consider merging or let me know something?

2 weeks have passed and I see that other providers (posted later) are already merged.

Since it costed me a lot of work, I would appreciate if you can look at it.

Thanks

@BiswaViraj
Copy link
Contributor

@collimarco Sorry for the delay 🙏🏼 ,
I will review this in few hours.
For now can you please, fix the merge conflicts

@BiswaViraj BiswaViraj self-assigned this Oct 12, 2023
@collimarco
Copy link
Contributor Author

@BiswaViraj

Thanks for the reply!

It seems that the only conflicts are the package files (some generated automatically)... Maybe it's better to fix them when you are merging this PR (to avoid further conflicts)?

Otherwise please let me know what exact steps I should perform

@BiswaViraj
Copy link
Contributor

@collimarco, just saw the spell check CI test is also failing, please fix it by adding the words to the https://github.com/novuhq/novu/blob/next/.cspell.json file

@@ -72,6 +72,7 @@
"@novu/netcore": "^0.19.0",
"@novu/nodemailer": "^0.19.0",
"@novu/one-signal": "^0.19.0",
"@novu/pushpad": "^0.16.3",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"@novu/pushpad": "^0.16.3",
"@novu/pushpad": "^0.20.0-alpha.1",

After fixing the merge conflicts, update this version to ^0.20.0-alpha.1

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@collimarco , I think this change was removed after the rebase, can you update this and then run npm run setup:project to generate the new pnpm-lock file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@BiswaViraj Ok, done! Do you need anything else for merging?

## Usage

```javascript
FILL IN THE INITIALIZATION USAGE
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add an example usage here

@@ -0,0 +1,82 @@
{
"name": "@novu/pushpad",
"version": "0.16.3",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"version": "0.16.3",
"version": "0.20.0-alpha.1",

"pnpm": "^7.26.0"
},
"dependencies": {
"@novu/stateless": "0.16.3",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"@novu/stateless": "0.16.3",
"@novu/stateless": "^0.20.0-alpha.1",

Comment on lines 1 to 32
import { PushpadPushProvider } from './pushpad.provider';

test('should trigger pushpad library correctly', async () => {
const provider = new PushpadPushProvider({
apiKey: 'test-token',
appId: '012345',
});
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a test case where the response is mocked,
For reference, you can check other providers spec files

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add dark Square version of the logo here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add light square version of logo here.

@collimarco
Copy link
Contributor Author

@BiswaViraj

Thanks for the suggestions! I made the requested changes.

For the test I see that other providers do this for example:

  const spy = jest
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
    // @ts-expect-error
    .spyOn(provider.oneSignal, 'createNotification')

However the Pushpad library uses new Pushpad.Notification({}) and not something like pushpadInstance.createNotification(). This means that it is hard to mock / stub in this case. I also admit that I am mainly a Ruby developer and I don't have much experience with tests in TypeScript. Do you have any suggestion on how to test that?

@BiswaViraj
Copy link
Contributor

@collimarco , umm, I see what you mean, it will be difficult, in that case, you can try to mock the provider's sendMessage

  const spy = jest
    .spyOn(provider, 'sendMessage')
    .mockImplementation(async () => {
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      return {} as any;
    });

@collimarco
Copy link
Contributor Author

@BiswaViraj Yes it's hard to test.

Do you mean something like this?

import { PushpadPushProvider } from './pushpad.provider';

test('should trigger pushpad library correctly', async () => {
  const provider = new PushpadPushProvider({
    apiKey: 'test-token',
    appId: '012345',
  });

  const spy = jest
    .spyOn(provider, 'sendMessage')
    .mockImplementation(async () => {
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      return {} as any;
    });
});

That would mock the entire method and nothing is tested... that is why I omitted the test.

Otherwise the only solution would be to extract this code to a separate method:

    const notification = new Pushpad.Notification({
      project: this.pushpad,
      body: options.content,
      title: options.title,
    });

And then stub the method that instantiates the new notification.

However, again, all the testing would be against a mock notification, and that is not really useful.

@LetItRock
Copy link
Contributor

hey @collimarco! 👋 thanks a lot for your contribution to Novu, we really appreciate that 🤝

A few suggestions from my side about the mocking. Basically in your tests, you need to cover the logic that is in the PushpadPushProvider.sendMessage and verify that when the options.target exists then the notification.deliverTo is called, otherwise notification.broadcast.

In order to do that you have to mock the pushpad module and provide the mock implementation for the Pushpad.Notification.

Something like this should work:

jest.mock('pushpad', () => {
  class MockNotification {
    async deliverTo(target, callback) {
      callback(null, { id: 12345 });
    }

    async broadcast(callback) {
      callback(null, { id: 54321 });
    }
  }

  return {
    ...jest.requireActual('pushpad'),
    Notification: MockNotification,
  };
});

Then in your tests, you can create the instance of the PushpadPushProvider and call the sendMessage function and then verify if the id returned is the one that is from the MockNotification.deliverTo or MockNotification.broadcast.

Hope this helps ;)
P.S. Please also update your branch with the latest changes.

@collimarco
Copy link
Contributor Author

collimarco commented Oct 13, 2023

@LetItRock Thanks for the suggestion, I appreciate it!

I was already working on this and found a similar solution: can you check if it's ok? (test is passing)

66ce7d4

Otherwise if you prefer your code I can change it.

P.S. Please also update your branch with the latest changes.

I only see the package files conflicting: can you please fix that when you merge the branch?

Otherwise, how do you recommend to proceed? Do you want me to make a git merge origin/master on my feature branch?

@LetItRock
Copy link
Contributor

I was already working on this and found a similar solution: can you check if it's ok? (test is passing)

yes, this approach also works 🙌 but please just add one more test that will cover the case when the broadcast function is called ;)

P.S. Please also update your branch with the latest changes.

I only see the package files conflicting: can you please fix that when you merge the branch?

Otherwise, how do you recommend to proceed? Do you want me to make a git merge origin/master on my feature branch?

you can follow the suggested steps here: https://stackoverflow.com/a/7244456/2383407, the branch that you have to merge/rebase is next

@collimarco
Copy link
Contributor Author

@LetItRock Yes, no problem.

But I have a doubt about the Novu architecture that is blocking me: is options.target always set to some user IDs (never empty)? Or it can be null to send a broadcast message to everyone? Or you use an empty array [] when you want to send to everyone?

@LetItRock
Copy link
Contributor

@LetItRock Yes, no problem.

But I have a doubt about the Novu architecture that is blocking me: is options.target always set to some user IDs (never empty)? Or it can be null to send a broadcast message to everyone? Or you use an empty array [] when you want to send to everyone?

If you check the target types, it says that it's string[] meaning you shouldn't expect it to be null.
The target is something that we call "device tokens" that are stored on the subscriber of the notification. The Novu logic that is calling the sendMessage will make sure that it will be never called with [] nor null.

@collimarco
Copy link
Contributor Author

@LetItRock @BiswaViraj

I have:

  • removed Pushpad broadcast notifications since Novu doesn't support it
  • completed the tests
  • rebased my feature on upstream/next

Please merge it or let me know something.

Thanks

@collimarco
Copy link
Contributor Author

If you want to try the Pushpad provider directly with Novu you can create a free account:

  1. Go to Pushpad and create an account (only name and email are required for sign up, no credit card)
  2. Create a new sender (e.g. Name: "My sender")
  3. Create a new project (e.g. Sender: "My sender", Name: "Example project", Website: "example.com")
  4. Go to project settings to get the project ID (called AppID in Novu)
  5. Go to your account settings -> Access tokens and create a new token (called ApiKey in Novu)
  6. You should be able to send a notification to a recipient from Novu (e.g. target = "myuser567")
  7. If you go to your Pushpad project and click Notifications -> Details you should see that the notification is sent to the user with id = "myuser567"

@LetItRock
Copy link
Contributor

LetItRock commented Oct 13, 2023

If you want to try the Pushpad provider directly with Novu you can create a free account:

  1. Go to Pushpad and create an account (only name and email are required for sign up, no credit card)
  2. Create a new sender (e.g. Name: "My sender")
  3. Create a new project (e.g. Sender: "My sender", Name: "Example project", Website: "example.com")
  4. Go to project settings to get the project ID (called AppID in Novu)
  5. Go to your account settings -> Access tokens and create a new token (called ApiKey in Novu)
  6. You should be able to send a notification to a recipient from Novu (e.g. target = "myuser567")
  7. If you go to your Pushpad project and click Notifications -> Details you should see that the notification is sent to the user with id = "myuser567"

hey 👋 I was able to successfully integrate Novu with a Pushpad.
But unfortunately in the activity feed, I do see that the ID is returned as null, check the screenshot below. It's happening because the code in the PushpadPushProvider.sendMessage is not "awaiting" for the notification.deliverTo callback result. In order to return the ID appropriately, you need to wrap notification.deliverTo code in the promise and "await" for the result. Also please include in the test the check for the id field.

Screenshot 2023-10-13 at 23 20 40 Screenshot 2023-10-13 at 23 48 03

@collimarco
Copy link
Contributor Author

@LetItRock

Thanks!

I have fixed the error with this commit:
e556773

Let me know

@LetItRock
Copy link
Contributor

@LetItRock

Thanks!

I have fixed the error with this commit: e556773

Let me know

Looks good, thanks! 🙌 let's see if the pipelines will pass :)

@LetItRock
Copy link
Contributor

@collimarco can you please pull the latest and resolve the conflicts? thanks! 🤝

@collimarco
Copy link
Contributor Author

@LetItRock Thanks for approving this!

I already rebased everything the other day, spending a lot of time, then the branch next moved forward, and now I would need to rebase again... It's really a waste of time.

Can you please rebase it when you actually merge it? Otherwise if I do the work again and you don't merge immediately it's useless...

@LetItRock
Copy link
Contributor

@LetItRock Thanks for approving this!

I already rebased everything the other day, spending a lot of time, then the branch next moved forward, and now I would need to rebase again... It's really a waste of time.

Can you please rebase it when you actually merge it? Otherwise if I do the work again and you don't merge immediately it's useless...

ok, we will handle it, thanks! ;)

@LetItRock
Copy link
Contributor

hey @collimarco! 👋 can you please give me permission to push to your fork?

@collimarco
Copy link
Contributor Author

@LetItRock I have added you to the forked repository with write access. Let me know if you need anything else.

@LetItRock LetItRock merged commit 7405994 into novuhq:next Oct 25, 2023
24 of 27 checks passed
@collimarco
Copy link
Contributor Author

@LetItRock Thanks for merging this!

Do you know when this will become available in the next release and in your cloud version?

When it becomes publicly available and released, I am planning to publish a blog post or documentation on our website.

@LetItRock
Copy link
Contributor

@LetItRock Thanks for merging this!

Do you know when this will become available in the next release and in your cloud version?

hey @collimarco 👋 thank you too for the contribution 🤝
We've just deployed the cloud version v0.21.0; Pushpad integration is included.

When it becomes publicly available and released, I am planning to publish a blog post or documentation on our website.

that's cool, let us know about that ;)

@collimarco
Copy link
Contributor Author

collimarco commented Oct 27, 2023

@LetItRock Sure, I'll let you know :)

@collimarco
Copy link
Contributor Author

@LetItRock

let us know about that ;)

Here's the blog post 🎉 https://pushpad.xyz/blog/sending-web-push-notifications-from-novu-notification-center

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

🚀 Feature: Pushpad provider for web push notifications
3 participants