@live-change/user-frontend 0.9.200 → 0.9.203

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,13 +4,15 @@ import App from '@live-change/framework'
4
4
  import randomProfile from 'random-profile-generator'
5
5
  import { withBrowser } from './withBrowser.js'
6
6
  import { useSecretCode, sleep } from './steps.js'
7
+ import { e2eSuite } from './e2eSuite.js'
7
8
 
8
9
  const app = App.app()
9
10
  const email = randomProfile.profile().firstName.toLowerCase() + '@test.com'
10
11
  const email2 = randomProfile.profile().firstName.toLowerCase() + '2@test.com'
11
12
  const happyPath = false
12
13
 
13
- test('connect email with code', async () => {
14
+ e2eSuite('connectEmailCode', () => {
15
+ test('connect email with code', async () => {
14
16
  await withBrowser(async (page, env) => {
15
17
  const user = app.generateUid()
16
18
 
@@ -62,4 +64,5 @@ test('connect email with code', async () => {
62
64
  assert.ok(page.url().includes('/connect-finished'))
63
65
  }
64
66
  })
67
+ })
65
68
  })
@@ -4,13 +4,15 @@ import App from '@live-change/framework'
4
4
  import randomProfile from 'random-profile-generator'
5
5
  import { withBrowser } from './withBrowser.js'
6
6
  import { useSecretLink } from './steps.js'
7
+ import { e2eSuite } from './e2eSuite.js'
7
8
 
8
9
  const app = App.app()
9
10
  const email = randomProfile.profile().firstName.toLowerCase() + '@test.com'
10
11
  const email2 = randomProfile.profile().firstName.toLowerCase() + '2@test.com'
11
12
  const happyPath = false
12
13
 
13
- test('connect email with link', async () => {
14
+ e2eSuite('connectEmailLink', () => {
15
+ test('connect email with link', async () => {
14
16
  await withBrowser(async (page, env) => {
15
17
  const user = app.generateUid()
16
18
 
@@ -59,4 +61,5 @@ test('connect email with link', async () => {
59
61
  await page.getByText('Link used').waitFor({ state: 'visible' })
60
62
  }
61
63
  })
64
+ })
62
65
  })
@@ -3,12 +3,14 @@ import assert from 'node:assert'
3
3
  import App from '@live-change/framework'
4
4
  import randomProfile from 'random-profile-generator'
5
5
  import { withBrowser } from './withBrowser.js'
6
+ import { e2eSuite } from './e2eSuite.js'
6
7
 
7
8
  const app = App.app()
8
9
  const name = randomProfile.profile().firstName.toLowerCase()
9
10
  const email = name + '@test.com'
10
11
 
11
- test('delete account', async () => {
12
+ e2eSuite('delete', () => {
13
+ test('delete account', async () => {
12
14
  await withBrowser(async (page, env) => {
13
15
  const user = app.generateUid()
14
16
 
@@ -49,4 +51,5 @@ test('delete account', async () => {
49
51
  const deletedEmail = await Email.get(email)
50
52
  assert.strictEqual(!!deletedEmail, false, 'email deleted')
51
53
  })
54
+ })
52
55
  })
@@ -3,6 +3,7 @@ import assert from 'node:assert'
3
3
  import App from '@live-change/framework'
4
4
  import randomProfile from 'random-profile-generator'
5
5
  import { withBrowser } from './withBrowser.js'
6
+ import { e2eSuite } from './e2eSuite.js'
6
7
 
7
8
  const app = App.app()
8
9
  const name = randomProfile.profile().firstName.toLowerCase()
@@ -10,7 +11,8 @@ const email = name + '@test.com'
10
11
  const email2 = name + '2@test.com'
11
12
  const happyPath = false
12
13
 
13
- test('disconnect email', async () => {
14
+ e2eSuite('disconnectEmail', () => {
15
+ test('disconnect email', async () => {
14
16
  await withBrowser(async (page, env) => {
15
17
  const user = app.generateUid()
16
18
 
@@ -40,4 +42,5 @@ test('disconnect email', async () => {
40
42
  await page.locator('span.pi-times').waitFor({ state: 'hidden' })
41
43
  }
42
44
  })
45
+ })
43
46
  })
@@ -0,0 +1,12 @@
1
+ import { after, describe } from 'node:test'
2
+ import { disposeTestEnv } from './env.js'
3
+
4
+ export function e2eSuite(name: string, define: () => void): void {
5
+ describe(name, () => {
6
+ after(async () => {
7
+ await disposeTestEnv()
8
+ process.exit(0)
9
+ })
10
+ define()
11
+ })
12
+ }
package/e2e/env.ts CHANGED
@@ -42,7 +42,17 @@ export type TestEnv = {
42
42
  grabObject: (serviceName: string, modelName: string, id: string) => Promise<unknown>
43
43
  }
44
44
 
45
+ type TestServerInstance = InstanceType<typeof TestServer>
46
+
45
47
  let envPromise: Promise<TestEnv> | null = null
48
+ let testServer: TestServerInstance | null = null
49
+
50
+ export async function disposeTestEnv(): Promise<void> {
51
+ const server = testServer
52
+ testServer = null
53
+ envPromise = null
54
+ if (server) await server.dispose()
55
+ }
46
56
 
47
57
  function haveService(server: InstanceType<typeof TestServer>, name: string) {
48
58
  const service = server.apiServer.services.services.find((s: { name: string }) => s.name === name)
@@ -79,23 +89,12 @@ export async function getTestEnv(): Promise<TestEnv> {
79
89
  console.log('waiting for front to be ready...')
80
90
  await waitForServerReady(server.url!)
81
91
  console.log('front ready')
92
+ testServer = server
82
93
 
83
94
  process.on('beforeExit', () => {
84
- server.dispose()
95
+ void disposeTestEnv()
85
96
  })
86
97
 
87
- // When running under node:test, register a global teardown that disposes the server
88
- // and forces process exit so the test run finishes cleanly.
89
- try {
90
- const { after } = await import('node:test')
91
- after(async () => {
92
- await server.dispose()
93
- process.exit(0)
94
- })
95
- } catch {
96
- // not running under node:test, ignore
97
- }
98
-
99
98
  const url = server.url!
100
99
  return {
101
100
  server,
@@ -5,11 +5,13 @@ import randomProfile from 'random-profile-generator'
5
5
  import passwordGenerator from 'generate-password'
6
6
  import { withBrowser } from './withBrowser.js'
7
7
  import { useSecretCode } from './steps.js'
8
+ import { e2eSuite } from './e2eSuite.js'
8
9
 
9
10
  const app = App.app()
10
11
  const email = randomProfile.profile().firstName.toLowerCase() + '@test.com'
11
12
 
12
- test('reset password with email code', async () => {
13
+ e2eSuite('resetPasswordWithEmailCode', () => {
14
+ test('reset password with email code', async () => {
13
15
  await withBrowser(async (page, env) => {
14
16
  const user = app.generateUid()
15
17
 
@@ -57,4 +59,5 @@ test('reset password with email code', async () => {
57
59
  await page.waitForURL('**/reset-password-finished', { timeout: 10000 })
58
60
  assert.ok(page.url().includes('/reset-password-finished'))
59
61
  })
62
+ })
60
63
  })
@@ -5,11 +5,13 @@ import randomProfile from 'random-profile-generator'
5
5
  import passwordGenerator from 'generate-password'
6
6
  import { withBrowser } from './withBrowser.js'
7
7
  import { useSecretLink } from './steps.js'
8
+ import { e2eSuite } from './e2eSuite.js'
8
9
 
9
10
  const app = App.app()
10
11
  const email = randomProfile.profile().firstName.toLowerCase() + '@test.com'
11
12
 
12
- test('reset password with email link', async () => {
13
+ e2eSuite('resetPasswordWithEmailLink', () => {
14
+ test('reset password with email link', async () => {
13
15
  await withBrowser(async (page, env) => {
14
16
  const user = app.generateUid()
15
17
 
@@ -57,4 +59,5 @@ test('reset password with email link', async () => {
57
59
  await page.waitForURL('**/reset-password-finished', { timeout: 10000 })
58
60
  assert.ok(page.url().includes('/reset-password-finished'))
59
61
  })
62
+ })
60
63
  })
@@ -4,12 +4,14 @@ import App from '@live-change/framework'
4
4
  import randomProfile from 'random-profile-generator'
5
5
  import passwordGenerator from 'generate-password'
6
6
  import { withBrowser } from './withBrowser.js'
7
+ import { e2eSuite } from './e2eSuite.js'
7
8
 
8
9
  const app = App.app()
9
10
  const name = randomProfile.profile().firstName.toLowerCase()
10
11
  const email = name + '@test.com'
11
12
 
12
- test('set password', async () => {
13
+ e2eSuite('setPassword', () => {
14
+ test('set password', async () => {
13
15
  await withBrowser(async (page, env) => {
14
16
  const user = app.generateUid()
15
17
  const User = env.haveModel('user', 'User')
@@ -67,4 +69,5 @@ test('set password', async () => {
67
69
  'password changed'
68
70
  )
69
71
  })
72
+ })
70
73
  })
@@ -4,6 +4,7 @@ import App from '@live-change/framework'
4
4
  import randomProfile from 'random-profile-generator'
5
5
  import { withBrowser } from './withBrowser.js'
6
6
  import { useSecretCode } from './steps.js'
7
+ import { e2eSuite } from './e2eSuite.js'
7
8
 
8
9
  const app = App.app()
9
10
  const randomUserData = randomProfile.profile()
@@ -11,7 +12,8 @@ const randomUserData = randomProfile.profile()
11
12
  (randomUserData as { firstName: string }).firstName.toLowerCase() + '@test.com'
12
13
  const happyPath = false
13
14
 
14
- test('sign in with email code', async () => {
15
+ e2eSuite('signInEmailCode', () => {
16
+ test('sign in with email code', async () => {
15
17
  await withBrowser(async (page, env) => {
16
18
  const user = app.generateUid()
17
19
  const email = (randomUserData as { email: string }).email
@@ -55,4 +57,5 @@ test('sign in with email code', async () => {
55
57
  assert.ok(page.url().includes('/user/sign-in-finished'))
56
58
  }
57
59
  })
60
+ })
58
61
  })
@@ -4,6 +4,7 @@ import App from '@live-change/framework'
4
4
  import randomProfile from 'random-profile-generator'
5
5
  import { withBrowser } from './withBrowser.js'
6
6
  import { useSecretLink } from './steps.js'
7
+ import { e2eSuite } from './e2eSuite.js'
7
8
 
8
9
  const app = App.app()
9
10
  const randomUserData = randomProfile.profile()
@@ -11,7 +12,8 @@ const randomUserData = randomProfile.profile()
11
12
  (randomUserData as { firstName: string }).firstName.toLowerCase() + '@test.com'
12
13
  const happyPath = false
13
14
 
14
- test('sign in with email link', async () => {
15
+ e2eSuite('signInEmailLink', () => {
16
+ test('sign in with email link', async () => {
15
17
  await withBrowser(async (page, env) => {
16
18
  const user = app.generateUid()
17
19
  const email = (randomUserData as { email: string }).email
@@ -55,4 +57,5 @@ test('sign in with email link', async () => {
55
57
  await page.getByText('Link used').waitFor({ state: 'visible' })
56
58
  }
57
59
  })
60
+ })
58
61
  })
@@ -5,13 +5,15 @@ import randomProfile from 'random-profile-generator'
5
5
  import crypto from 'crypto'
6
6
  import passwordGenerator from 'generate-password'
7
7
  import { withBrowser } from './withBrowser.js'
8
+ import { e2eSuite } from './e2eSuite.js'
8
9
 
9
10
  const app = App.app()
10
11
  const randomUserData = randomProfile.profile()
11
12
  ;(randomUserData as { email?: string }).email =
12
13
  (randomUserData as { firstName: string }).firstName.toLowerCase() + '@test.com'
13
14
 
14
- test('sign in with email and password', async () => {
15
+ e2eSuite('signInEmailPassword', () => {
16
+ test('sign in with email and password', async () => {
15
17
  await withBrowser(async (page, env) => {
16
18
  const user = app.generateUid()
17
19
  const email = (randomUserData as { email: string }).email
@@ -48,4 +50,5 @@ test('sign in with email and password', async () => {
48
50
  )
49
51
  assert.strictEqual(clientUser, (authenticatedUserData as { user: string }).user, 'user authenticated')
50
52
  })
53
+ })
51
54
  })
@@ -3,12 +3,14 @@ import assert from 'node:assert'
3
3
  import App from '@live-change/framework'
4
4
  import randomProfile from 'random-profile-generator'
5
5
  import { withBrowser } from './withBrowser.js'
6
+ import { e2eSuite } from './e2eSuite.js'
6
7
 
7
8
  const app = App.app()
8
9
  const name = randomProfile.profile().firstName.toLowerCase()
9
10
  const email = name + '@test.com'
10
11
 
11
- test('sign out', async () => {
12
+ e2eSuite('signOut', () => {
13
+ test('sign out', async () => {
12
14
  await withBrowser(async (page, env) => {
13
15
  const user = app.generateUid()
14
16
  const User = env.haveModel('user', 'User')
@@ -42,4 +44,5 @@ test('sign out', async () => {
42
44
  assert.strictEqual(!!authenticatedUserData, false, 'no server user')
43
45
  assert.strictEqual(!!clientUser2, false, 'no client user')
44
46
  })
47
+ })
45
48
  })
@@ -3,13 +3,15 @@ import assert from 'node:assert'
3
3
  import randomProfile from 'random-profile-generator'
4
4
  import { withBrowser } from './withBrowser.js'
5
5
  import { useSecretCode } from './steps.js'
6
+ import { e2eSuite } from './e2eSuite.js'
6
7
 
7
8
  const user = randomProfile.profile()
8
9
  ;(user as { email?: string }).email =
9
10
  (user as { firstName: string }).firstName.toLowerCase() + '@test.com'
10
11
  const happyPath = false
11
12
 
12
- test('sign up with email code', async () => {
13
+ e2eSuite('signUpEmailCode', () => {
14
+ test('sign up with email code', async () => {
13
15
  await withBrowser(async (page, env) => {
14
16
  await page.goto(env.url + '/user/sign-up-email', { waitUntil: 'networkidle' })
15
17
  await page.fill('input#email', (user as { email: string }).email)
@@ -43,4 +45,5 @@ test('sign up with email code', async () => {
43
45
  assert.ok(page.url().includes('/user/sign-up-finished'))
44
46
  }
45
47
  })
48
+ })
46
49
  })
@@ -3,13 +3,15 @@ import assert from 'node:assert'
3
3
  import randomProfile from 'random-profile-generator'
4
4
  import { withBrowser } from './withBrowser.js'
5
5
  import { useSecretLink } from './steps.js'
6
+ import { e2eSuite } from './e2eSuite.js'
6
7
 
7
8
  const user = randomProfile.profile()
8
9
  ;(user as { email?: string }).email =
9
10
  (user as { firstName: string }).firstName.toLowerCase() + '@test.com'
10
11
  const happyPath = false
11
12
 
12
- test('sign up with email link', async () => {
13
+ e2eSuite('signUpEmailLink', () => {
14
+ test('sign up with email link', async () => {
13
15
  await withBrowser(async (page, env) => {
14
16
  await page.goto(env.url + '/user/sign-up-email', { waitUntil: 'networkidle' })
15
17
  await page.fill('input#email', (user as { email: string }).email)
@@ -43,4 +45,5 @@ test('sign up with email link', async () => {
43
45
  await page.getByText('Link used').waitFor({ state: 'visible' })
44
46
  }
45
47
  })
48
+ })
46
49
  })
@@ -7,7 +7,7 @@ export async function withBrowser(
7
7
  fn: (page: Page, env: TestEnv) => Promise<void>
8
8
  ): Promise<void> {
9
9
  const env = await getTestEnv()
10
- const browser = await chromium.launch({ headless: false })
10
+ const browser = await chromium.launch({ headless: process.env.SHOW_BROWSER ? false : true })
11
11
  const context = await browser.newContext()
12
12
  const page = await context.newPage()
13
13
  try {
@@ -12,9 +12,9 @@
12
12
  class="mr-0 rounded-full border-1 border-surface-400 dark:border-surface-600 w-12 max-w-none" />
13
13
  </span>
14
14
  </a>
15
- <div class="align-items-center flex-grow-1 justify-content-between hidden absolute w-full md:w-auto
16
- bg-surface-0 dark:bg-surface-950 dark:border-1 dark:border-surface-800
17
- right-0 md:right-auto top-full z-5 shadow">
15
+ <div :class="['align-items-center flex-grow-1 justify-content-between hidden absolute w-full md:w-auto',
16
+ 'bg-surface-0 dark:bg-surface-950 dark:border-1 dark:border-surface-800',
17
+ 'right-0 md:right-auto top-full z-5 shadow', menuClass]" :style="menuStyle">
18
18
  <loading-zone suspense>
19
19
  <template v-slot:loading>
20
20
  <div class="flex items-center justify-center top-0 left-0 notifications-loading">
@@ -44,13 +44,22 @@
44
44
  import ProgressSpinner from "primevue/progressspinner"
45
45
  import UserMenu from "./UserMenu.vue"
46
46
 
47
- import { ref, computed, onMounted, toRefs } from 'vue'
47
+ import { ref, computed, onMounted, toRefs, defineProps } from 'vue'
48
48
 
49
49
  const isMounted = ref(false)
50
50
  onMounted(() => isMounted.value = true)
51
51
 
52
- import { usePath, live, useClient } from '@live-change/vue3-ssr'
52
+ const props = defineProps({
53
+ menuClass: {
54
+ default: ''
55
+ },
56
+ menuStyle: {
57
+ default: ''
58
+ }
59
+ })
60
+ const { menuClass, menuStyle } = toRefs(props)
53
61
 
62
+ import { usePath, live, useClient } from '@live-change/vue3-ssr'
54
63
  const client = useClient()
55
64
 
56
65
  const ownerData = computed(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@live-change/user-frontend",
3
- "version": "0.9.200",
3
+ "version": "0.9.203",
4
4
  "scripts": {
5
5
  "memDev": "tsx --inspect --expose-gc server/start.js memDev --enableSessions --initScript ./init.js --dbAccess",
6
6
  "localDevInit": "tsx server/start.js localDev --enableSessions --initScript ./init.js --dbAccess",
@@ -37,29 +37,29 @@
37
37
  },
38
38
  "type": "module",
39
39
  "dependencies": {
40
- "@live-change/cli": "^0.9.200",
41
- "@live-change/dao": "^0.9.200",
42
- "@live-change/dao-vue3": "^0.9.200",
43
- "@live-change/dao-websocket": "^0.9.200",
44
- "@live-change/email-service": "^0.9.200",
45
- "@live-change/framework": "^0.9.200",
46
- "@live-change/identicon-service": "^0.9.200",
47
- "@live-change/image-frontend": "^0.9.200",
48
- "@live-change/message-authentication-service": "^0.9.200",
49
- "@live-change/notification-service": "^0.9.200",
50
- "@live-change/password-authentication-service": "^0.9.200",
51
- "@live-change/pattern": "^0.9.200",
52
- "@live-change/secret-code-service": "^0.9.200",
53
- "@live-change/secret-link-service": "^0.9.200",
54
- "@live-change/security-frontend": "^0.9.200",
55
- "@live-change/security-service": "^0.9.200",
56
- "@live-change/session-service": "^0.9.200",
57
- "@live-change/timer-service": "^0.9.200",
58
- "@live-change/upload-service": "^0.9.200",
59
- "@live-change/user-identification-service": "^0.9.200",
60
- "@live-change/user-service": "^0.9.200",
61
- "@live-change/vue3-components": "^0.9.200",
62
- "@live-change/vue3-ssr": "^0.9.200",
40
+ "@live-change/cli": "^0.9.203",
41
+ "@live-change/dao": "^0.9.203",
42
+ "@live-change/dao-vue3": "^0.9.203",
43
+ "@live-change/dao-websocket": "^0.9.203",
44
+ "@live-change/email-service": "^0.9.203",
45
+ "@live-change/framework": "^0.9.203",
46
+ "@live-change/identicon-service": "^0.9.203",
47
+ "@live-change/image-frontend": "^0.9.203",
48
+ "@live-change/message-authentication-service": "^0.9.203",
49
+ "@live-change/notification-service": "^0.9.203",
50
+ "@live-change/password-authentication-service": "^0.9.203",
51
+ "@live-change/pattern": "^0.9.203",
52
+ "@live-change/secret-code-service": "^0.9.203",
53
+ "@live-change/secret-link-service": "^0.9.203",
54
+ "@live-change/security-frontend": "^0.9.203",
55
+ "@live-change/security-service": "^0.9.203",
56
+ "@live-change/session-service": "^0.9.203",
57
+ "@live-change/timer-service": "^0.9.203",
58
+ "@live-change/upload-service": "^0.9.203",
59
+ "@live-change/user-identification-service": "^0.9.203",
60
+ "@live-change/user-service": "^0.9.203",
61
+ "@live-change/vue3-components": "^0.9.203",
62
+ "@live-change/vue3-ssr": "^0.9.203",
63
63
  "@vueuse/core": "^12.3.0",
64
64
  "codeceptjs-assert": "^0.0.5",
65
65
  "codeceptjs-video-helper": "0.1.3",
@@ -80,7 +80,7 @@
80
80
  "wtfnode": "^0.9.1"
81
81
  },
82
82
  "devDependencies": {
83
- "@live-change/codeceptjs-helper": "^0.9.200",
83
+ "@live-change/codeceptjs-helper": "^0.9.203",
84
84
  "codeceptjs": "^3.7.6",
85
85
  "generate-password": "1.7.1",
86
86
  "playwright": "1.49.1",
@@ -91,5 +91,5 @@
91
91
  "author": "Michał Łaszczewski <michal@laszczewski.pl>",
92
92
  "license": "BSD-3-Clause",
93
93
  "description": "",
94
- "gitHead": "a509834e600a546297faa7d1534b6f52e66d2e66"
94
+ "gitHead": "4d4ce413fe747da2c398eb4ad378e37cc81874b3"
95
95
  }