-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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
[NV-3735]: Improve launch darkly #5517
Changes from all commits
53647b3
4200cd7
1066caf
0e7da6a
9389165
952ec8f
e992ffd
a98073d
961a334
00bf34e
a34a72b
953339e
037d946
59b0edb
c1cc6c9
30da614
43273d9
2ab55ab
6ed5769
81ad742
1a3ad79
9bf9e28
be3c6b9
c511889
f155b3d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,10 @@ | ||
import * as capitalize from 'lodash.capitalize'; | ||
import { JobTitleEnum, jobTitleToLabelMapper } from '@novu/shared'; | ||
import { FeatureFlagsKeysEnum, JobTitleEnum, jobTitleToLabelMapper } from '@novu/shared'; | ||
|
||
describe('User Sign-up and Login', function () { | ||
beforeEach(function () { | ||
cy.mockFeatureFlags({ [FeatureFlagsKeysEnum.IS_INFORMATION_ARCHITECTURE_ENABLED]: false }); | ||
}); | ||
describe('Sign up', function () { | ||
beforeEach(function () { | ||
cy.clearDatabase(); | ||
|
@@ -10,7 +13,9 @@ describe('User Sign-up and Login', function () { | |
|
||
it('should allow a visitor to sign-up, login, and logout', function () { | ||
cy.intercept('**/organization/**/switch').as('appSwitch'); | ||
cy.visit('/auth/signup'); | ||
cy.waitLoadFeatureFlags(() => { | ||
cy.visit('/auth/signup'); | ||
}); | ||
cy.getByTestId('fullName').type('Test User'); | ||
cy.getByTestId('email').type('[email protected]'); | ||
cy.getByTestId('password').type('usEr_password_123!'); | ||
|
@@ -30,7 +35,9 @@ describe('User Sign-up and Login', function () { | |
}); | ||
|
||
it('should show account already exists when signing up with already registered mail', function () { | ||
cy.visit('/auth/signup'); | ||
cy.waitLoadFeatureFlags(() => { | ||
cy.visit('/auth/signup'); | ||
}); | ||
cy.getByTestId('fullName').type('Test User'); | ||
cy.getByTestId('email').type('[email protected]'); | ||
cy.getByTestId('password').type('usEr_password_123!'); | ||
|
@@ -40,7 +47,9 @@ describe('User Sign-up and Login', function () { | |
}); | ||
|
||
it('should show invalid email error when signing up with invalid email', function () { | ||
cy.visit('/auth/signup'); | ||
cy.waitLoadFeatureFlags(() => { | ||
cy.visit('/auth/signup'); | ||
}); | ||
cy.getByTestId('fullName').type('Test User'); | ||
cy.getByTestId('email').type('[email protected]'); | ||
cy.getByTestId('password').type('usEr_password_123!'); | ||
|
@@ -54,7 +63,9 @@ describe('User Sign-up and Login', function () { | |
if (!isCI) return; | ||
|
||
cy.intercept('**/organization/**/switch').as('appSwitch'); | ||
cy.visit('/auth/signup'); | ||
cy.waitLoadFeatureFlags(() => { | ||
cy.visit('/auth/signup'); | ||
}); | ||
|
||
cy.loginWithGitHub(); | ||
|
||
|
@@ -82,7 +93,9 @@ describe('User Sign-up and Login', function () { | |
const gitHubUserEmail = Cypress.env('GITHUB_USER_EMAIL'); | ||
|
||
cy.intercept('**/organization/**/switch').as('appSwitch'); | ||
cy.visit('/auth/signup'); | ||
cy.waitLoadFeatureFlags(() => { | ||
cy.visit('/auth/signup'); | ||
}); | ||
cy.getByTestId('fullName').type('Test User'); | ||
cy.getByTestId('email').type(gitHubUserEmail); | ||
cy.getByTestId('password').type('usEr_password_123!'); | ||
|
@@ -115,13 +128,19 @@ describe('User Sign-up and Login', function () { | |
}); | ||
|
||
it('should request a password reset flow', function () { | ||
cy.visit('/auth/reset/request'); | ||
cy.waitLoadFeatureFlags(() => { | ||
cy.visit('/auth/reset/request'); | ||
}); | ||
cy.getByTestId('email').type(this.session.user.email); | ||
cy.getByTestId('submit-btn').click(); | ||
cy.getByTestId('success-screen-reset').should('be.visible'); | ||
|
||
cy.task('passwordResetToken', this.session.user._id).then((token) => { | ||
cy.visit('/auth/reset/' + token); | ||
}); | ||
|
||
// unfortunately there seems to be a timing issue in in which inputs are disabled | ||
cy.wait(500); | ||
cy.getByTestId('password').type('A123e3e3e3!'); | ||
cy.getByTestId('password-repeat').focus().type('A123e3e3e3!'); | ||
|
||
|
@@ -137,18 +156,24 @@ describe('User Sign-up and Login', function () { | |
|
||
it('should redirect to the dashboard page when a token exists in query', function () { | ||
cy.initializeSession({ disableLocalStorage: true }).then((session) => { | ||
cy.visit('/auth/login?token=' + session.token); | ||
cy.waitLoadFeatureFlags(() => { | ||
cy.visit('/auth/login?token=' + session.token); | ||
}); | ||
cy.location('pathname').should('equal', '/workflows'); | ||
}); | ||
}); | ||
|
||
it('should be redirect login with no auth', function () { | ||
cy.visit('/'); | ||
cy.waitLoadFeatureFlags(() => { | ||
cy.visit('/'); | ||
}); | ||
cy.location('pathname').should('equal', '/auth/login'); | ||
}); | ||
|
||
it('should successfully login the user', function () { | ||
cy.visit('/auth/login'); | ||
cy.waitLoadFeatureFlags(() => { | ||
cy.visit('/auth/login'); | ||
}); | ||
|
||
cy.getByTestId('email').type('[email protected]'); | ||
cy.getByTestId('password').type('123qwe!@#'); | ||
|
@@ -157,7 +182,9 @@ describe('User Sign-up and Login', function () { | |
}); | ||
|
||
it('should show incorrect email or password error when authenticating with bad credentials', function () { | ||
cy.visit('/auth/login'); | ||
cy.waitLoadFeatureFlags(() => { | ||
cy.visit('/auth/login'); | ||
}); | ||
|
||
cy.getByTestId('email').type('[email protected]'); | ||
cy.getByTestId('password').type('123456'); | ||
|
@@ -166,7 +193,9 @@ describe('User Sign-up and Login', function () { | |
}); | ||
|
||
it('should show invalid email error when authenticating with invalid email', function () { | ||
cy.visit('/auth/login'); | ||
cy.waitLoadFeatureFlags(() => { | ||
cy.visit('/auth/login'); | ||
}); | ||
|
||
cy.getByTestId('email').type('[email protected]'); | ||
cy.getByTestId('password').type('123456'); | ||
|
@@ -175,7 +204,9 @@ describe('User Sign-up and Login', function () { | |
}); | ||
|
||
it('should show incorrect email or password error when authenticating with non-existing email', function () { | ||
cy.visit('/auth/login'); | ||
cy.waitLoadFeatureFlags(() => { | ||
cy.visit('/auth/login'); | ||
}); | ||
|
||
cy.getByTestId('email').type('[email protected]'); | ||
cy.getByTestId('password').type('123456'); | ||
|
@@ -197,6 +228,8 @@ describe('User Sign-up and Login', function () { | |
cy.getByTestId('password').type('123qwe!@#'); | ||
cy.getByTestId('submit-btn').click(); | ||
|
||
cy.waitLoadFeatureFlags(); | ||
|
||
cy.location('pathname').should('equal', '/workflows'); | ||
|
||
// setting current time in future, to simulate expired token | ||
|
@@ -207,6 +240,8 @@ describe('User Sign-up and Login', function () { | |
|
||
cy.visit('/subscribers'); | ||
|
||
cy.waitLoadFeatureFlags(); | ||
|
||
// checking if token is removed from local storage | ||
cy.getLocalStorage('auth_token').should('be.null'); | ||
// checking if user is redirected to login page | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,15 @@ | ||
import { CONTEXT_PATH, LAUNCH_DARKLY_CLIENT_SIDE_ID, SegmentProvider } from '@novu/shared-web'; | ||
import { Loader } from '@mantine/core'; | ||
import { colors } from '@novu/design-system'; | ||
import { CONTEXT_PATH, SegmentProvider } from '@novu/shared-web'; | ||
import * as Sentry from '@sentry/react'; | ||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; | ||
import { withLDProvider } from 'launchdarkly-react-client-sdk'; | ||
import { PropsWithChildren } from 'react'; | ||
import { HelmetProvider } from 'react-helmet-async'; | ||
import { BrowserRouter } from 'react-router-dom'; | ||
import { api } from './api/api.client'; | ||
import { LaunchDarklyProvider } from './components/launch-darkly'; | ||
import { AuthProvider } from './components/providers/AuthProvider'; | ||
import { css } from './styled-system/css'; | ||
|
||
const defaultQueryFn = async ({ queryKey }: { queryKey: string }) => { | ||
const response = await api.get(`${queryKey[0]}`); | ||
|
@@ -22,28 +25,41 @@ const queryClient = new QueryClient({ | |
}, | ||
}); | ||
|
||
/** Full-page loader that uses color-preferences for background */ | ||
const fallbackDisplay = ( | ||
<div | ||
className={css({ | ||
h: '100dvh', | ||
w: '100dvw', | ||
display: 'grid', | ||
placeItems: 'center', | ||
bg: 'surface.page', | ||
// Root element may not have loaded so rely on OS | ||
_osDark: { bg: 'legacy.BGDark' }, | ||
_osLight: { bg: 'legacy.BGLight' }, | ||
})} | ||
> | ||
<Loader size={64} variant="bars" color={colors.gradientMiddle} /> | ||
</div> | ||
); | ||
|
||
/** | ||
* Centralized Provider hierarchy. | ||
*/ | ||
const Providers: React.FC<PropsWithChildren<{}>> = ({ children }) => { | ||
return ( | ||
<SegmentProvider> | ||
<HelmetProvider> | ||
<QueryClientProvider client={queryClient}> | ||
<BrowserRouter basename={CONTEXT_PATH}> | ||
<QueryClientProvider client={queryClient}> | ||
<AuthProvider>{children}</AuthProvider> | ||
</QueryClientProvider> | ||
<AuthProvider> | ||
<LaunchDarklyProvider fallbackDisplay={fallbackDisplay}> | ||
<HelmetProvider>{children}</HelmetProvider> | ||
</LaunchDarklyProvider> | ||
</AuthProvider> | ||
</BrowserRouter> | ||
</HelmetProvider> | ||
</QueryClientProvider> | ||
</SegmentProvider> | ||
); | ||
}; | ||
|
||
export default Sentry.withProfiler( | ||
withLDProvider({ | ||
clientSideID: LAUNCH_DARKLY_CLIENT_SIDE_ID, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗒 note (non-blocking): Moved LD provider to its own file in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❓ question: why move to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Most of our other similar providers are there, and many of the related behaviors / imports (i.e. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤓 nitpick (non-blocking): I suggest keeping it closer to the source of the web app unless we are sure it would be reused. Otherwise, we might end up with a landfill. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with @LetItRock. I feel that we might be overusing shared packages on some occasions. Other than that, great choice to split it into a separate component. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds good, thanks for the feedback! Updated |
||
reactOptions: { | ||
useCamelCaseFlagKeys: false, | ||
}, | ||
})(Providers) | ||
); | ||
export default Sentry.withProfiler(Providers); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🗒 note (non-blocking): the
/auth/application
is not a protected route 😨