login.ts 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import { runScript } from './hostAdminClient'
  2. export const DEFAULT_PASSWORD = 'Passw0rd!'
  3. const createdUsers = new Set<string>()
  4. export function resetCreatedUsersCache() {
  5. createdUsers.clear()
  6. }
  7. export async function createMongoUser({
  8. email,
  9. isAdmin = false,
  10. }: {
  11. email: string
  12. isAdmin?: boolean
  13. }) {
  14. const t0 = Math.floor(Date.now() / 1000)
  15. const { stdout } = await runScript({
  16. cwd: 'services/web',
  17. script: 'modules/server-ce-scripts/scripts/create-user.js',
  18. args: [`--email=${email}`, `--admin=${isAdmin}`],
  19. })
  20. const [url] = stdout.match(/http:\/\/.+\/user\/activate\?token=\S+/)!
  21. const userId = new URL(url, location.origin).searchParams.get('user_id')!
  22. const signupDate = parseInt(userId.slice(0, 8), 16)
  23. if (signupDate < t0) {
  24. return { url, exists: true }
  25. }
  26. return { url, exists: false }
  27. }
  28. export function ensureUserExists({
  29. email,
  30. password = DEFAULT_PASSWORD,
  31. isAdmin = false,
  32. }: {
  33. email: string
  34. password?: string
  35. isAdmin?: boolean
  36. }) {
  37. let url: string
  38. let exists: boolean
  39. before(async function () {
  40. exists = createdUsers.has(email)
  41. if (exists) return
  42. ;({ url, exists } = await createMongoUser({ email, isAdmin }))
  43. })
  44. before(function () {
  45. if (exists) return
  46. activateUser(url, password)
  47. cy.then(() => {
  48. createdUsers.add(email)
  49. })
  50. })
  51. }
  52. export function login(username: string, password = DEFAULT_PASSWORD) {
  53. cy.session(
  54. ['via-login', username, password],
  55. () => {
  56. cy.visit('/login')
  57. cy.get('input[name="email"]').type(username)
  58. cy.get('input[name="password"]').type(password)
  59. cy.findByRole('button', { name: 'Login' }).click()
  60. cy.url().should('contain', '/project')
  61. },
  62. {
  63. cacheAcrossSpecs: true,
  64. async validate() {
  65. // Hit a cheap endpoint that is behind AuthenticationController.requireLogin().
  66. cy.request({ url: '/user/personal_info', followRedirect: false }).then(
  67. response => {
  68. expect(response.status).to.equal(200)
  69. }
  70. )
  71. },
  72. }
  73. )
  74. }
  75. let activateRateLimitState = { count: 0, reset: 0 }
  76. export function resetActivateUserRateLimit() {
  77. activateRateLimitState = { count: 0, reset: 0 }
  78. }
  79. function handleActivateUserRateLimit() {
  80. cy.then(() => {
  81. activateRateLimitState.count++
  82. if (activateRateLimitState.reset < Date.now()) {
  83. activateRateLimitState.reset = Date.now() + 65_000
  84. activateRateLimitState.count = 1
  85. } else if (activateRateLimitState.count >= 6) {
  86. cy.wait(activateRateLimitState.reset - Date.now())
  87. activateRateLimitState.count = 1
  88. }
  89. })
  90. }
  91. export function activateUser(url: string, password = DEFAULT_PASSWORD) {
  92. handleActivateUserRateLimit()
  93. cy.session(url, () => {
  94. cy.visit(url)
  95. cy.url().then(url => {
  96. if (url.includes('/login')) return
  97. cy.url().should('contain', '/user/activate')
  98. cy.get('input[name="password"]').type(password)
  99. cy.findByRole('button', { name: 'Activate' }).click()
  100. cy.url().should('contain', '/project')
  101. })
  102. })
  103. }