@nextsparkjs/theme-productivity 0.1.0-beta.37 → 0.1.0-beta.39
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.
- package/lib/selectors.ts +2 -3
- package/package.json +3 -2
- package/tests/cypress/src/session-helpers.ts +112 -41
- package/tests/cypress.config.ts +8 -23
package/lib/selectors.ts
CHANGED
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
* - Cypress tests (via tests/cypress/src/selectors.ts)
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { createSelectorHelpers } from '@nextsparkjs/
|
|
13
|
-
import { CORE_SELECTORS } from '@nextsparkjs/core/lib/test/core-selectors'
|
|
12
|
+
import { createSelectorHelpers, CORE_SELECTORS } from '@nextsparkjs/testing/selectors'
|
|
14
13
|
|
|
15
14
|
// =============================================================================
|
|
16
15
|
// BLOCK SELECTORS
|
|
@@ -202,5 +201,5 @@ export type ThemeSelectorsType = typeof THEME_SELECTORS
|
|
|
202
201
|
export type BlockSelectorsType = typeof BLOCK_SELECTORS
|
|
203
202
|
export type EntitySelectorsType = typeof ENTITY_SELECTORS
|
|
204
203
|
export type KanbanSelectorsType = typeof KANBAN_SELECTORS
|
|
205
|
-
export type { Replacements } from '@nextsparkjs/
|
|
204
|
+
export type { Replacements } from '@nextsparkjs/testing/selectors'
|
|
206
205
|
export { CORE_SELECTORS }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextsparkjs/theme-productivity",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.39",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./config/theme.config.ts",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
"react": "^19.0.0",
|
|
13
13
|
"react-dom": "^19.0.0",
|
|
14
14
|
"zod": "^4.0.0",
|
|
15
|
-
"@nextsparkjs/core": "0.1.0-beta.
|
|
15
|
+
"@nextsparkjs/core": "0.1.0-beta.39",
|
|
16
|
+
"@nextsparkjs/testing": "0.1.0-beta.39"
|
|
16
17
|
},
|
|
17
18
|
"nextspark": {
|
|
18
19
|
"type": "theme",
|
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
* Productivity Theme Session Helpers
|
|
3
3
|
*
|
|
4
4
|
* Direct login functions for Productivity theme tests using theme-specific users.
|
|
5
|
-
*
|
|
5
|
+
* Uses API-based login for faster and more stable authentication.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { DevKeyring } from '../../../../../../test/cypress/src/classes/components/auth/DevKeyring.js'
|
|
9
|
-
|
|
10
8
|
/**
|
|
11
9
|
* Productivity Test Users - from app.config.ts devKeyring
|
|
12
10
|
*/
|
|
@@ -17,22 +15,85 @@ export const PRODUCTIVITY_USERS = {
|
|
|
17
15
|
MEMBER_MARKETING: 'prod_member_marcos@nextspark.dev', // Marcos Silva - Marketing Hub (member)
|
|
18
16
|
} as const
|
|
19
17
|
|
|
18
|
+
// Default test password for demo users
|
|
19
|
+
const TEST_PASSWORD = Cypress.env('TEST_PASSWORD') || 'Test1234'
|
|
20
|
+
const API_TIMEOUT = 60000
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* API login helper
|
|
24
|
+
*/
|
|
25
|
+
function apiLogin(email: string, password: string = TEST_PASSWORD): Cypress.Chainable<boolean> {
|
|
26
|
+
return cy.request({
|
|
27
|
+
method: 'POST',
|
|
28
|
+
url: '/api/auth/sign-in/email',
|
|
29
|
+
body: { email, password },
|
|
30
|
+
timeout: API_TIMEOUT,
|
|
31
|
+
failOnStatusCode: false
|
|
32
|
+
}).then((response) => {
|
|
33
|
+
if (response.status === 200) {
|
|
34
|
+
return true
|
|
35
|
+
} else {
|
|
36
|
+
cy.log(`⚠️ API login failed with status ${response.status}`)
|
|
37
|
+
return false
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Setup team context after login
|
|
44
|
+
*/
|
|
45
|
+
function setupTeamContext(preferredRole?: string) {
|
|
46
|
+
cy.request({
|
|
47
|
+
method: 'GET',
|
|
48
|
+
url: '/api/v1/teams',
|
|
49
|
+
timeout: API_TIMEOUT,
|
|
50
|
+
failOnStatusCode: false
|
|
51
|
+
}).then((teamsResponse) => {
|
|
52
|
+
if (teamsResponse.status === 200 && teamsResponse.body?.data?.length > 0) {
|
|
53
|
+
const teams = teamsResponse.body.data
|
|
54
|
+
let selectedTeam = teams[0]
|
|
55
|
+
if (preferredRole) {
|
|
56
|
+
const teamWithRole = teams.find((t: { role: string }) => t.role === preferredRole)
|
|
57
|
+
if (teamWithRole) {
|
|
58
|
+
selectedTeam = teamWithRole
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const teamId = selectedTeam.id
|
|
62
|
+
cy.log(`✅ Setting active team: ${selectedTeam.name} (${teamId})`)
|
|
63
|
+
cy.window().then((win) => {
|
|
64
|
+
win.localStorage.setItem('activeTeamId', teamId)
|
|
65
|
+
})
|
|
66
|
+
cy.request({
|
|
67
|
+
method: 'POST',
|
|
68
|
+
url: '/api/v1/teams/switch',
|
|
69
|
+
body: { teamId },
|
|
70
|
+
timeout: API_TIMEOUT,
|
|
71
|
+
failOnStatusCode: false
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
|
|
20
77
|
/**
|
|
21
78
|
* Login as Productivity Owner (Patricia Torres)
|
|
22
79
|
* Has owner role in Product Team and Marketing Hub
|
|
23
|
-
* Session is cached and reused across tests
|
|
24
80
|
*/
|
|
25
81
|
export function loginAsProductivityOwner() {
|
|
26
82
|
cy.session('productivity-owner-session', () => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
83
|
+
apiLogin(PRODUCTIVITY_USERS.OWNER).then((success) => {
|
|
84
|
+
if (success) {
|
|
85
|
+
cy.visit('/dashboard', { timeout: 60000 })
|
|
86
|
+
}
|
|
87
|
+
cy.url().should('include', '/dashboard')
|
|
88
|
+
setupTeamContext()
|
|
89
|
+
})
|
|
32
90
|
}, {
|
|
33
91
|
validate: () => {
|
|
34
|
-
cy.
|
|
35
|
-
|
|
92
|
+
cy.request({
|
|
93
|
+
url: '/api/auth/get-session',
|
|
94
|
+
timeout: API_TIMEOUT,
|
|
95
|
+
failOnStatusCode: false
|
|
96
|
+
}).its('status').should('eq', 200)
|
|
36
97
|
}
|
|
37
98
|
})
|
|
38
99
|
}
|
|
@@ -40,19 +101,23 @@ export function loginAsProductivityOwner() {
|
|
|
40
101
|
/**
|
|
41
102
|
* Login as Productivity Admin (Lucas Luna)
|
|
42
103
|
* Has admin role in Product Team, member role in Marketing Hub
|
|
43
|
-
* Session is cached and reused across tests
|
|
44
104
|
*/
|
|
45
105
|
export function loginAsProductivityAdmin() {
|
|
46
106
|
cy.session('productivity-admin-session', () => {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
107
|
+
apiLogin(PRODUCTIVITY_USERS.ADMIN).then((success) => {
|
|
108
|
+
if (success) {
|
|
109
|
+
cy.visit('/dashboard', { timeout: 60000 })
|
|
110
|
+
}
|
|
111
|
+
cy.url().should('include', '/dashboard')
|
|
112
|
+
setupTeamContext()
|
|
113
|
+
})
|
|
52
114
|
}, {
|
|
53
115
|
validate: () => {
|
|
54
|
-
cy.
|
|
55
|
-
|
|
116
|
+
cy.request({
|
|
117
|
+
url: '/api/auth/get-session',
|
|
118
|
+
timeout: API_TIMEOUT,
|
|
119
|
+
failOnStatusCode: false
|
|
120
|
+
}).its('status').should('eq', 200)
|
|
56
121
|
}
|
|
57
122
|
})
|
|
58
123
|
}
|
|
@@ -60,19 +125,23 @@ export function loginAsProductivityAdmin() {
|
|
|
60
125
|
/**
|
|
61
126
|
* Login as Productivity Member - Product Team (Diana Rios)
|
|
62
127
|
* Has member role in Product Team only
|
|
63
|
-
* Session is cached and reused across tests
|
|
64
128
|
*/
|
|
65
129
|
export function loginAsProductivityMember() {
|
|
66
130
|
cy.session('productivity-member-session', () => {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
131
|
+
apiLogin(PRODUCTIVITY_USERS.MEMBER_PRODUCT).then((success) => {
|
|
132
|
+
if (success) {
|
|
133
|
+
cy.visit('/dashboard', { timeout: 60000 })
|
|
134
|
+
}
|
|
135
|
+
cy.url().should('include', '/dashboard')
|
|
136
|
+
setupTeamContext('member')
|
|
137
|
+
})
|
|
72
138
|
}, {
|
|
73
139
|
validate: () => {
|
|
74
|
-
cy.
|
|
75
|
-
|
|
140
|
+
cy.request({
|
|
141
|
+
url: '/api/auth/get-session',
|
|
142
|
+
timeout: API_TIMEOUT,
|
|
143
|
+
failOnStatusCode: false
|
|
144
|
+
}).its('status').should('eq', 200)
|
|
76
145
|
}
|
|
77
146
|
})
|
|
78
147
|
}
|
|
@@ -80,26 +149,28 @@ export function loginAsProductivityMember() {
|
|
|
80
149
|
/**
|
|
81
150
|
* Login as Productivity Member - Marketing Hub (Marcos Silva)
|
|
82
151
|
* Has member role in Marketing Hub only
|
|
83
|
-
* Session is cached and reused across tests
|
|
84
152
|
*/
|
|
85
153
|
export function loginAsProductivityMemberMarketing() {
|
|
86
154
|
cy.session('productivity-member-marketing-session', () => {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
155
|
+
apiLogin(PRODUCTIVITY_USERS.MEMBER_MARKETING).then((success) => {
|
|
156
|
+
if (success) {
|
|
157
|
+
cy.visit('/dashboard', { timeout: 60000 })
|
|
158
|
+
}
|
|
159
|
+
cy.url().should('include', '/dashboard')
|
|
160
|
+
setupTeamContext('member')
|
|
161
|
+
})
|
|
92
162
|
}, {
|
|
93
163
|
validate: () => {
|
|
94
|
-
cy.
|
|
95
|
-
|
|
164
|
+
cy.request({
|
|
165
|
+
url: '/api/auth/get-session',
|
|
166
|
+
timeout: API_TIMEOUT,
|
|
167
|
+
failOnStatusCode: false
|
|
168
|
+
}).its('status').should('eq', 200)
|
|
96
169
|
}
|
|
97
170
|
})
|
|
98
171
|
}
|
|
99
172
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
export
|
|
104
|
-
return loginAsProductivityOwner()
|
|
105
|
-
}
|
|
173
|
+
// Aliases for convenience
|
|
174
|
+
export const loginAsOwner = loginAsProductivityOwner
|
|
175
|
+
export const loginAsAdmin = loginAsProductivityAdmin
|
|
176
|
+
export const loginAsMember = loginAsProductivityMember
|
package/tests/cypress.config.ts
CHANGED
|
@@ -8,20 +8,14 @@
|
|
|
8
8
|
import { defineConfig } from 'cypress'
|
|
9
9
|
import path from 'path'
|
|
10
10
|
import fs from 'fs'
|
|
11
|
-
import { fileURLToPath } from 'url'
|
|
12
11
|
|
|
13
|
-
//
|
|
14
|
-
const __filename = fileURLToPath(import.meta.url)
|
|
15
|
-
const __dirname = path.dirname(__filename)
|
|
12
|
+
// __dirname works natively with CommonJS module resolution (tsconfig.cypress.json)
|
|
16
13
|
|
|
17
14
|
// Paths relative to this config file
|
|
18
15
|
const themeRoot = path.resolve(__dirname, '..')
|
|
19
16
|
const projectRoot = path.resolve(__dirname, '../../../..')
|
|
20
17
|
const narrationsOutputDir = path.join(__dirname, 'cypress/videos/narrations')
|
|
21
18
|
|
|
22
|
-
// Detect if running in npm mode (no packages/core folder) vs monorepo
|
|
23
|
-
const isNpmMode = !fs.existsSync(path.join(projectRoot, 'packages/core'))
|
|
24
|
-
|
|
25
19
|
// Load environment variables
|
|
26
20
|
import dotenv from 'dotenv'
|
|
27
21
|
dotenv.config({ path: path.join(projectRoot, '.env') })
|
|
@@ -34,22 +28,13 @@ export default defineConfig({
|
|
|
34
28
|
// Base URL for the application
|
|
35
29
|
baseUrl: `http://localhost:${port}`,
|
|
36
30
|
|
|
37
|
-
// Spec patterns: theme tests
|
|
38
|
-
specPattern:
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
// Monorepo: core tests + theme tests
|
|
45
|
-
path.join(projectRoot, 'packages/core/tests/cypress/e2e/core/**/*.cy.{js,ts}'),
|
|
46
|
-
path.join(__dirname, 'cypress/e2e/**/*.cy.{js,ts}'),
|
|
47
|
-
],
|
|
48
|
-
|
|
49
|
-
// Support file (theme-local in npm mode, core in monorepo)
|
|
50
|
-
supportFile: isNpmMode
|
|
51
|
-
? path.join(__dirname, 'cypress/support/e2e.ts')
|
|
52
|
-
: path.join(projectRoot, 'packages/core/tests/cypress/support/e2e.ts'),
|
|
31
|
+
// Spec patterns: theme tests only
|
|
32
|
+
specPattern: [
|
|
33
|
+
path.join(__dirname, 'cypress/e2e/**/*.cy.{js,ts}'),
|
|
34
|
+
],
|
|
35
|
+
|
|
36
|
+
// Support file (always theme-local)
|
|
37
|
+
supportFile: path.join(__dirname, 'cypress/support/e2e.ts'),
|
|
53
38
|
|
|
54
39
|
// Fixtures folder (theme-specific)
|
|
55
40
|
fixturesFolder: path.join(__dirname, 'cypress/fixtures'),
|