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

chore(dashboard): user journey smoke tests #7124

Merged
merged 45 commits into from
Feb 24, 2025

Conversation

LetItRock
Copy link
Contributor

@LetItRock LetItRock commented Nov 25, 2024

What changed? Why was the change needed?

Enterprise PR: https://github.com/novuhq/packages-enterprise/pull/273

Dashboard - the core user journeys smoke tests that cover:

  • dashboard-created workflow
  • code-created workflow

Screenshots

Screenshot 2024-11-25 at 13 59 28

@LetItRock LetItRock self-assigned this Nov 25, 2024
Copy link

linear bot commented Nov 25, 2024

Copy link

netlify bot commented Nov 25, 2024

Deploy Preview for novu-stg-vite-dashboard-poc ready!

Name Link
🔨 Latest commit fa860f3
🔍 Latest deploy log https://app.netlify.com/sites/novu-stg-vite-dashboard-poc/deploys/674d7a4f4008e900085d165d
😎 Deploy Preview https://deploy-preview-7124.dashboard-v2.novu-staging.co
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@@ -121,3 +121,4 @@ backups/

# Nest.js auto-generated metadata (https://docs.nestjs.com/recipes/swc#monorepo-and-cli-plugins)
src/metadata.ts
src/.env.test
Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed the .env.test file from git, because the local file that I used for the tests had sensitive clerk credentials

@@ -5,6 +5,7 @@
"type": "module",
"scripts": {
"start": "vite",
"start:test": "vite --mode test",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

run dashboard and use .env.test file

Comment on lines +91 to +92
"@novu/dal": "workspace:*",
"@novu/testing": "workspace:*",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

used to initialize the api session

Comment on lines +12 to +14
const fileName = fileURLToPath(import.meta.url);
const dirName = dirname(fileName);
dotenv.config({ path: path.resolve(dirName, '.env.playwright') });
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because the Dashboard project is configured with "type": "module" this is how we can import the playwright env variables.

Comment on lines 54 to 57
{
name: 'setup',
testMatch: /global\.setup\.ts/,
},
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The global setup test file will initialize the Clerk session for all tests. Using this approach, we can say that for some tests, we don't want to have a session, and then we will be able to verify, for example, the sign-in/up flows.

Comment on lines 19 to 43
bridgeServer = new BridgeServer({ secretKey: session.environment.apiKeys[0].key, apiUrl: process.env.API_URL });

const newWorkflow = workflow(workflowId, async ({ step }) => {
await step.inApp(
inAppStepId,
async (controls) => {
return {
subject: `Hi ${controls.name}! You've been invited to join the Novu project`,
body,
};
},
{
controlSchema: {
type: 'object',
properties: {
name: { type: 'string', default: 'John' },
},
} as const,
}
);
});
await bridgeServer.start({ workflows: [newWorkflow] });
await session.testAgent.post(`/v1/bridge/sync`).send({
bridgeUrl: bridgeServer.serverPath,
});
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Run the bridge server and sync the workflow

await session.testAgent.post(`/v1/bridge/sync`).send({
bridgeUrl: bridgeServer.serverPath,
});
await page.waitForTimeout(2000);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

should be removed

Comment on lines 10 to 15
/**
* TODO: Currently we are running tests with a single Clerk user and organization.
* This approach has a drawback that the tests are not independent from each other and write the data to the same organization.
* We should consider creating a new Clerk user and organization for each test using the @clerk/backend package.
* Then initialize the BE session with the new Clerk user and organization and update Clerk user metadata from the newly created session.
*/
Copy link
Contributor Author

Choose a reason for hiding this comment

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

hopefully, it explains the problem well

Copy link
Contributor

Choose a reason for hiding this comment

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

Correct! We should leverage Clerk Backend API, create a user before every run, sign in with that user, and then delete the user at the end.

Regarding the need for Clerk webhooks during user and organization creation, I suggest connecting to Mongo directly from the test code using the response of the Clerk API to create the user and organization record the application needs to function.

On user deletion, I don't think we need to do anything in Mongo as we run in a dockerized environment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll think about this, as it will require reimplementing all the current setup.

@@ -0,0 +1,3 @@
{
"type": "commonjs"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The dal and testing packages are CJS modules which can't be imported by the ESM modules.
So this is the trick (together with tsconfig.json) to say "please allow me to import" in my test files :D

Copy link
Contributor

Choose a reason for hiding this comment

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

😢

Copy link
Contributor

Choose a reason for hiding this comment

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

@LetItRock Since we wrote dedicated E2E helpers in the Dashboard, do we need @novu/testing afterall?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

the @novu/testing is not needed, I made it in a way that the tests setup is independent of it

private memberRepository = getEERepository<MemberRepository>('MemberRepository');
private memberRepository: MemberRepository;

constructor({ mockClerkClient = true }: { mockClerkClient?: boolean } = {}) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

For the Dashboard E2E tests we don't want to mock the Clerk client, because we initialize the Clerk session with a real user that has the org and metadata that is used by the Dashboard code.

Copy link

pkg-pr-new bot commented Nov 25, 2024

Open in Stackblitz

@novu/client

npm i https://pkg.pr.new/novuhq/novu/@novu/client@7124

@novu/framework

npm i https://pkg.pr.new/novuhq/novu/@novu/framework@7124

@novu/js

npm i https://pkg.pr.new/novuhq/novu/@novu/js@7124

@novu/nest

npm i https://pkg.pr.new/novuhq/novu/@novu/nest@7124

@novu/headless

npm i https://pkg.pr.new/novuhq/novu/@novu/headless@7124

@novu/nextjs

npm i https://pkg.pr.new/novuhq/novu/@novu/nextjs@7124

@novu/node

npm i https://pkg.pr.new/novuhq/novu/@novu/node@7124

@novu/notification-center

npm i https://pkg.pr.new/novuhq/novu/@novu/notification-center@7124

novu

npm i https://pkg.pr.new/novuhq/novu@7124

@novu/providers

npm i https://pkg.pr.new/novuhq/novu/@novu/providers@7124

@novu/react

npm i https://pkg.pr.new/novuhq/novu/@novu/react@7124

@novu/react-native

npm i https://pkg.pr.new/novuhq/novu/@novu/react-native@7124

@novu/shared

npm i https://pkg.pr.new/novuhq/novu/@novu/shared@7124

@novu/stateless

npm i https://pkg.pr.new/novuhq/novu/@novu/stateless@7124

commit: 5d0de32

@LetItRock LetItRock requested review from a team and scopsy and removed request for a team November 25, 2024 15:52
Comment on lines +74 to +79
touch .env
echo VITE_LAUNCH_DARKLY_CLIENT_SIDE_ID=${{ secrets.LAUNCH_DARKLY_CLIENT_SIDE_ID }} >> .env
echo VITE_API_HOSTNAME=http://127.0.0.1:1336 >> .env
echo VITE_WEBSOCKET_HOSTNAME=http://127.0.0.1:1340 >> .env
echo VITE_LEGACY_DASHBOARD_URL=http://127.0.0.1:4200 >> .env
echo VITE_CLERK_PUBLISHABLE_KEY=${{ secrets.CLERK_E2E_PUBLISHABLE_KEY }} >> .env
Copy link
Contributor Author

Choose a reason for hiding this comment

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

.env file for the Dashboard

Comment on lines +84 to +93
touch .env.playwright
echo NOVU_ENTERPRISE=true >> .env.playwright
echo NEW_RELIC_ENABLED=false >> .env.playwright
echo NEW_RELIC_APP_NAME=Novu >> .env.playwright
echo MONGO_URL=mongodb://127.0.0.1:27017/novu-test >> .env.playwright
echo API_URL=http://127.0.0.1:1336 >> .env.playwright
echo CLERK_ENABLED=true >> .env.playwright
echo CLERK_PUBLISHABLE_KEY=${{ secrets.CLERK_E2E_PUBLISHABLE_KEY }} >> .env.playwright
echo CLERK_SECRET_KEY=${{ secrets.CLERK_E2E_SECRET_KEY }} >> .env.playwright
echo NODE_ENV=test >> .env.playwright
Copy link
Contributor Author

Choose a reason for hiding this comment

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

.env file for the playwright, used to initialize the session, create, and sync users/orgs

Comment on lines +109 to +110
"@clerk/backend": "^1.6.2",
"@clerk/testing": "^1.3.27",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

used to create Clerk user/orgs and to sign-in into the app

Comment on lines +89 to +90
e.preventDefault();
e.stopPropagation();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

fix the bug - the click on remove button was causing the form submission

@@ -80,7 +80,7 @@ export const NodeBody = ({

return (
<HoverCard openDelay={300}>
<HoverCardTrigger>
<HoverCardTrigger asChild>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

react warning a nested in a

Comment on lines -29 to -31
return () => {
observer.disconnect();
};
Copy link
Contributor Author

Choose a reason for hiding this comment

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

react warning on that the callback is never called

@@ -0,0 +1,3 @@
{
"type": "commonjs"
Copy link
Contributor

Choose a reason for hiding this comment

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

😢

*/
await page.addInitScript((currentSession) => {
window.addEventListener('DOMContentLoaded', () => {
localStorage.setItem('nv_auth_token', currentSession.token);
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you know if this is necessary in Dashboard v2? If not mistaken this is V1 logic for the community auth.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it's the leftover from the old implementation, will remove it

await triggerWorkflowPage.triggerWorkflowBtnClick();
const activityPanel = await triggerWorkflowPage.getActivityPanel();
await expect(activityPanel).toBeVisible();
await expect(activityPanel.locator('span').filter({ hasText: workflowNameUpdated })).toBeVisible();
Copy link
Contributor

Choose a reason for hiding this comment

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

I suggest we run more assertions on the trigger page to ensure that the status is updated while running.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll do that in the PR that I've opened for the activity panel fix: #7768

@@ -0,0 +1,3 @@
{
"type": "commonjs"
Copy link
Contributor

Choose a reason for hiding this comment

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

@LetItRock Since we wrote dedicated E2E helpers in the Dashboard, do we need @novu/testing afterall?

import { TriggerWorkflowPage } from './page-object-models/trigger-workflow-page';

test('manage workflows', async ({ page }) => {
const workflowName = 'test-workflow';
Copy link
Contributor

@SokratisVidros SokratisVidros Feb 21, 2025

Choose a reason for hiding this comment

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

How about starting the flow from sign-up so that we test the onboarding?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

we should do it in a separate test as the test fixture is doing all the user setup logic

@LetItRock LetItRock merged commit ae191d8 into next Feb 24, 2025
16 checks passed
@LetItRock LetItRock deleted the nv-4795-dashboard-user-journey-smoke-tests branch February 24, 2025 18:13
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.

None yet

2 participants