samaro-uitest 1.0.0

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.
Files changed (111) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +336 -0
  3. package/bin/samaro-allure.js +172 -0
  4. package/bin/samaro-init.js +278 -0
  5. package/bin/samaro-test.js +36 -0
  6. package/config/index.d.ts +4 -0
  7. package/config/index.d.ts.map +1 -0
  8. package/config/index.js +11 -0
  9. package/config/index.js.map +1 -0
  10. package/config/index.ts +3 -0
  11. package/config/playwright.component.config.d.ts +12 -0
  12. package/config/playwright.component.config.d.ts.map +1 -0
  13. package/config/playwright.component.config.js +42 -0
  14. package/config/playwright.component.config.js.map +1 -0
  15. package/config/playwright.component.config.ts +60 -0
  16. package/config/playwright.config.d.ts +14 -0
  17. package/config/playwright.config.d.ts.map +1 -0
  18. package/config/playwright.config.js +53 -0
  19. package/config/playwright.config.js.map +1 -0
  20. package/config/playwright.config.ts +76 -0
  21. package/config/test-setup.ts +17 -0
  22. package/config/vitest.config.d.ts +13 -0
  23. package/config/vitest.config.d.ts.map +1 -0
  24. package/config/vitest.config.js +53 -0
  25. package/config/vitest.config.js.map +1 -0
  26. package/config/vitest.config.ts +64 -0
  27. package/dist/config/index.d.ts +4 -0
  28. package/dist/config/index.d.ts.map +1 -0
  29. package/dist/config/index.js +4 -0
  30. package/dist/config/index.js.map +1 -0
  31. package/dist/config/playwright.component.config.d.ts +12 -0
  32. package/dist/config/playwright.component.config.d.ts.map +1 -0
  33. package/dist/config/playwright.component.config.js +39 -0
  34. package/dist/config/playwright.component.config.js.map +1 -0
  35. package/dist/config/playwright.config.d.ts +14 -0
  36. package/dist/config/playwright.config.d.ts.map +1 -0
  37. package/dist/config/playwright.config.js +50 -0
  38. package/dist/config/playwright.config.js.map +1 -0
  39. package/dist/config/test-setup.d.ts +3 -0
  40. package/dist/config/test-setup.d.ts.map +1 -0
  41. package/dist/config/test-setup.js +17 -0
  42. package/dist/config/test-setup.js.map +1 -0
  43. package/dist/config/vitest.config.d.ts +13 -0
  44. package/dist/config/vitest.config.d.ts.map +1 -0
  45. package/dist/config/vitest.config.js +46 -0
  46. package/dist/config/vitest.config.js.map +1 -0
  47. package/dist/helpers/api.d.ts +69 -0
  48. package/dist/helpers/api.d.ts.map +1 -0
  49. package/dist/helpers/api.js +154 -0
  50. package/dist/helpers/api.js.map +1 -0
  51. package/dist/helpers/auth.d.ts +35 -0
  52. package/dist/helpers/auth.d.ts.map +1 -0
  53. package/dist/helpers/auth.js +96 -0
  54. package/dist/helpers/auth.js.map +1 -0
  55. package/dist/helpers/config.d.ts +34 -0
  56. package/dist/helpers/config.d.ts.map +1 -0
  57. package/dist/helpers/config.js +63 -0
  58. package/dist/helpers/config.js.map +1 -0
  59. package/dist/helpers/debug.d.ts +48 -0
  60. package/dist/helpers/debug.d.ts.map +1 -0
  61. package/dist/helpers/debug.js +76 -0
  62. package/dist/helpers/debug.js.map +1 -0
  63. package/dist/helpers/index.d.ts +6 -0
  64. package/dist/helpers/index.d.ts.map +1 -0
  65. package/dist/helpers/index.js +11 -0
  66. package/dist/helpers/index.js.map +1 -0
  67. package/dist/helpers/setup.d.ts +50 -0
  68. package/dist/helpers/setup.d.ts.map +1 -0
  69. package/dist/helpers/setup.js +95 -0
  70. package/dist/helpers/setup.js.map +1 -0
  71. package/dist/src/index.d.ts +16 -0
  72. package/dist/src/index.d.ts.map +1 -0
  73. package/dist/src/index.js +38 -0
  74. package/dist/src/index.js.map +1 -0
  75. package/helpers/api.d.ts +69 -0
  76. package/helpers/api.d.ts.map +1 -0
  77. package/helpers/api.js +163 -0
  78. package/helpers/api.js.map +1 -0
  79. package/helpers/api.ts +224 -0
  80. package/helpers/auth.d.ts +35 -0
  81. package/helpers/auth.d.ts.map +1 -0
  82. package/helpers/auth.js +104 -0
  83. package/helpers/auth.js.map +1 -0
  84. package/helpers/auth.ts +125 -0
  85. package/helpers/config.d.ts +34 -0
  86. package/helpers/config.d.ts.map +1 -0
  87. package/helpers/config.js +70 -0
  88. package/helpers/config.js.map +1 -0
  89. package/helpers/config.ts +80 -0
  90. package/helpers/debug.d.ts +48 -0
  91. package/helpers/debug.d.ts.map +1 -0
  92. package/helpers/debug.js +86 -0
  93. package/helpers/debug.js.map +1 -0
  94. package/helpers/debug.ts +111 -0
  95. package/helpers/index.d.ts +6 -0
  96. package/helpers/index.d.ts.map +1 -0
  97. package/helpers/index.js +47 -0
  98. package/helpers/index.js.map +1 -0
  99. package/helpers/index.ts +62 -0
  100. package/helpers/setup.d.ts +50 -0
  101. package/helpers/setup.d.ts.map +1 -0
  102. package/helpers/setup.js +137 -0
  103. package/helpers/setup.js.map +1 -0
  104. package/helpers/setup.ts +144 -0
  105. package/package.json +94 -0
  106. package/schematics/collection.json +11 -0
  107. package/schematics/ng-add/index.js +121 -0
  108. package/schematics/ng-add/schema.json +26 -0
  109. package/scripts/check-allure-results.js +269 -0
  110. package/types/allure.d.ts +76 -0
  111. package/types/global.d.ts +49 -0
@@ -0,0 +1,69 @@
1
+ import { APIRequestContext } from '@playwright/test';
2
+ export interface APIConfig {
3
+ baseURL: string;
4
+ }
5
+ export interface APIUser {
6
+ username: string;
7
+ email: string;
8
+ password: string;
9
+ }
10
+ export interface APIAuthResponse {
11
+ user: {
12
+ email: string;
13
+ token: string;
14
+ username: string;
15
+ bio: string | null;
16
+ image: string | null;
17
+ };
18
+ }
19
+ /**
20
+ * Get API configuration from environment variables
21
+ */
22
+ export declare function getAPIConfig(): APIConfig;
23
+ /**
24
+ * Register a user via API
25
+ */
26
+ export declare function registerUserViaAPI(request: APIRequestContext, user: APIUser): Promise<{
27
+ token: string;
28
+ username: string;
29
+ email: string;
30
+ }>;
31
+ /**
32
+ * Login a user via API
33
+ */
34
+ export declare function loginUserViaAPI(request: APIRequestContext, email: string, password: string): Promise<{
35
+ token: string;
36
+ username: string;
37
+ email: string;
38
+ }>;
39
+ /**
40
+ * Create an article via API
41
+ */
42
+ export declare function createArticleViaAPI(request: APIRequestContext, token: string, article: {
43
+ title: string;
44
+ description: string;
45
+ body: string;
46
+ tagList?: string[];
47
+ }): Promise<{
48
+ slug: string;
49
+ title: string;
50
+ }>;
51
+ /**
52
+ * Delete an article via API
53
+ */
54
+ export declare function deleteArticleViaAPI(request: APIRequestContext, token: string, slug: string): Promise<void>;
55
+ /**
56
+ * Update user via API
57
+ */
58
+ export declare function updateUserViaAPI(request: APIRequestContext, token: string, updates: {
59
+ email?: string;
60
+ bio?: string;
61
+ image?: string;
62
+ username?: string;
63
+ password?: string;
64
+ }): Promise<void>;
65
+ /**
66
+ * Get current user via API
67
+ */
68
+ export declare function getCurrentUserViaAPI(request: APIRequestContext, token: string): Promise<APIAuthResponse['user']>;
69
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;QACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;KACtB,CAAC;CACH;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,SAAS,CAIxC;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,iBAAiB,EAC1B,IAAI,EAAE,OAAO,GACZ,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAyB7D;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,iBAAiB,EAC1B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAyB7D;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,iBAAiB,EAC1B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;IACP,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,GACA,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAyB1C;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,iBAAiB,EAC1B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAiBf;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,iBAAiB,EAC1B,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;IACP,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GACA,OAAO,CAAC,IAAI,CAAC,CAmBf;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,iBAAiB,EAC1B,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAoBlC"}
package/helpers/api.js ADDED
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getAPIConfig = getAPIConfig;
4
+ exports.registerUserViaAPI = registerUserViaAPI;
5
+ exports.loginUserViaAPI = loginUserViaAPI;
6
+ exports.createArticleViaAPI = createArticleViaAPI;
7
+ exports.deleteArticleViaAPI = deleteArticleViaAPI;
8
+ exports.updateUserViaAPI = updateUserViaAPI;
9
+ exports.getCurrentUserViaAPI = getCurrentUserViaAPI;
10
+ /**
11
+ * Get API configuration from environment variables
12
+ */
13
+ function getAPIConfig() {
14
+ return {
15
+ baseURL: process.env.API_BASE || process.env.NG_API_URL || 'http://localhost:4200/api',
16
+ };
17
+ }
18
+ /**
19
+ * Register a user via API
20
+ */
21
+ async function registerUserViaAPI(request, user) {
22
+ const config = getAPIConfig();
23
+ try {
24
+ const response = await request.post(`${config.baseURL}/users`, {
25
+ data: { user },
26
+ headers: {
27
+ 'Content-Type': 'application/json',
28
+ },
29
+ });
30
+ if (!response.ok()) {
31
+ const errorText = await response.text();
32
+ throw new Error(`API registration failed (${response.status()}): ${errorText}`);
33
+ }
34
+ const data = await response.json();
35
+ return {
36
+ token: data.user.token,
37
+ username: data.user.username,
38
+ email: data.user.email,
39
+ };
40
+ }
41
+ catch (error) {
42
+ throw new Error(`Failed to register user via API: ${error}`);
43
+ }
44
+ }
45
+ /**
46
+ * Login a user via API
47
+ */
48
+ async function loginUserViaAPI(request, email, password) {
49
+ const config = getAPIConfig();
50
+ try {
51
+ const response = await request.post(`${config.baseURL}/users/login`, {
52
+ data: { user: { email, password } },
53
+ headers: {
54
+ 'Content-Type': 'application/json',
55
+ },
56
+ });
57
+ if (!response.ok()) {
58
+ const errorText = await response.text();
59
+ throw new Error(`API login failed (${response.status()}): ${errorText}`);
60
+ }
61
+ const data = await response.json();
62
+ return {
63
+ token: data.user.token,
64
+ username: data.user.username,
65
+ email: data.user.email,
66
+ };
67
+ }
68
+ catch (error) {
69
+ throw new Error(`Failed to login user via API: ${error}`);
70
+ }
71
+ }
72
+ /**
73
+ * Create an article via API
74
+ */
75
+ async function createArticleViaAPI(request, token, article) {
76
+ const config = getAPIConfig();
77
+ try {
78
+ const response = await request.post(`${config.baseURL}/articles`, {
79
+ data: { article },
80
+ headers: {
81
+ 'Content-Type': 'application/json',
82
+ 'Authorization': `Token ${token}`,
83
+ },
84
+ });
85
+ if (!response.ok()) {
86
+ const errorText = await response.text();
87
+ throw new Error(`API article creation failed (${response.status()}): ${errorText}`);
88
+ }
89
+ const data = await response.json();
90
+ return {
91
+ slug: data.article.slug,
92
+ title: data.article.title,
93
+ };
94
+ }
95
+ catch (error) {
96
+ throw new Error(`Failed to create article via API: ${error}`);
97
+ }
98
+ }
99
+ /**
100
+ * Delete an article via API
101
+ */
102
+ async function deleteArticleViaAPI(request, token, slug) {
103
+ const config = getAPIConfig();
104
+ try {
105
+ const response = await request.delete(`${config.baseURL}/articles/${slug}`, {
106
+ headers: {
107
+ 'Authorization': `Token ${token}`,
108
+ },
109
+ });
110
+ if (!response.ok()) {
111
+ const errorText = await response.text();
112
+ throw new Error(`API article deletion failed (${response.status()}): ${errorText}`);
113
+ }
114
+ }
115
+ catch (error) {
116
+ throw new Error(`Failed to delete article via API: ${error}`);
117
+ }
118
+ }
119
+ /**
120
+ * Update user via API
121
+ */
122
+ async function updateUserViaAPI(request, token, updates) {
123
+ const config = getAPIConfig();
124
+ try {
125
+ const response = await request.put(`${config.baseURL}/user`, {
126
+ data: { user: updates },
127
+ headers: {
128
+ 'Content-Type': 'application/json',
129
+ 'Authorization': `Token ${token}`,
130
+ },
131
+ });
132
+ if (!response.ok()) {
133
+ const errorText = await response.text();
134
+ throw new Error(`API user update failed (${response.status()}): ${errorText}`);
135
+ }
136
+ }
137
+ catch (error) {
138
+ throw new Error(`Failed to update user via API: ${error}`);
139
+ }
140
+ }
141
+ /**
142
+ * Get current user via API
143
+ */
144
+ async function getCurrentUserViaAPI(request, token) {
145
+ const config = getAPIConfig();
146
+ try {
147
+ const response = await request.get(`${config.baseURL}/user`, {
148
+ headers: {
149
+ 'Authorization': `Token ${token}`,
150
+ },
151
+ });
152
+ if (!response.ok()) {
153
+ const errorText = await response.text();
154
+ throw new Error(`API get user failed (${response.status()}): ${errorText}`);
155
+ }
156
+ const data = await response.json();
157
+ return data.user;
158
+ }
159
+ catch (error) {
160
+ throw new Error(`Failed to get current user via API: ${error}`);
161
+ }
162
+ }
163
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["api.ts"],"names":[],"mappings":"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"}
package/helpers/api.ts ADDED
@@ -0,0 +1,224 @@
1
+ import { APIRequestContext } from '@playwright/test';
2
+
3
+ export interface APIConfig {
4
+ baseURL: string;
5
+ }
6
+
7
+ export interface APIUser {
8
+ username: string;
9
+ email: string;
10
+ password: string;
11
+ }
12
+
13
+ export interface APIAuthResponse {
14
+ user: {
15
+ email: string;
16
+ token: string;
17
+ username: string;
18
+ bio: string | null;
19
+ image: string | null;
20
+ };
21
+ }
22
+
23
+ /**
24
+ * Get API configuration from environment variables
25
+ */
26
+ export function getAPIConfig(): APIConfig {
27
+ return {
28
+ baseURL: process.env.API_BASE || process.env.NG_API_URL || 'http://localhost:4200/api',
29
+ };
30
+ }
31
+
32
+ /**
33
+ * Register a user via API
34
+ */
35
+ export async function registerUserViaAPI(
36
+ request: APIRequestContext,
37
+ user: APIUser
38
+ ): Promise<{ token: string; username: string; email: string }> {
39
+ const config = getAPIConfig();
40
+
41
+ try {
42
+ const response = await request.post(`${config.baseURL}/users`, {
43
+ data: { user },
44
+ headers: {
45
+ 'Content-Type': 'application/json',
46
+ },
47
+ });
48
+
49
+ if (!response.ok()) {
50
+ const errorText = await response.text();
51
+ throw new Error(`API registration failed (${response.status()}): ${errorText}`);
52
+ }
53
+
54
+ const data = await response.json() as APIAuthResponse;
55
+ return {
56
+ token: data.user.token,
57
+ username: data.user.username,
58
+ email: data.user.email,
59
+ };
60
+ } catch (error) {
61
+ throw new Error(`Failed to register user via API: ${error}`);
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Login a user via API
67
+ */
68
+ export async function loginUserViaAPI(
69
+ request: APIRequestContext,
70
+ email: string,
71
+ password: string
72
+ ): Promise<{ token: string; username: string; email: string }> {
73
+ const config = getAPIConfig();
74
+
75
+ try {
76
+ const response = await request.post(`${config.baseURL}/users/login`, {
77
+ data: { user: { email, password } },
78
+ headers: {
79
+ 'Content-Type': 'application/json',
80
+ },
81
+ });
82
+
83
+ if (!response.ok()) {
84
+ const errorText = await response.text();
85
+ throw new Error(`API login failed (${response.status()}): ${errorText}`);
86
+ }
87
+
88
+ const data = await response.json() as APIAuthResponse;
89
+ return {
90
+ token: data.user.token,
91
+ username: data.user.username,
92
+ email: data.user.email,
93
+ };
94
+ } catch (error) {
95
+ throw new Error(`Failed to login user via API: ${error}`);
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Create an article via API
101
+ */
102
+ export async function createArticleViaAPI(
103
+ request: APIRequestContext,
104
+ token: string,
105
+ article: {
106
+ title: string;
107
+ description: string;
108
+ body: string;
109
+ tagList?: string[];
110
+ }
111
+ ): Promise<{ slug: string; title: string }> {
112
+ const config = getAPIConfig();
113
+
114
+ try {
115
+ const response = await request.post(`${config.baseURL}/articles`, {
116
+ data: { article },
117
+ headers: {
118
+ 'Content-Type': 'application/json',
119
+ 'Authorization': `Token ${token}`,
120
+ },
121
+ });
122
+
123
+ if (!response.ok()) {
124
+ const errorText = await response.text();
125
+ throw new Error(`API article creation failed (${response.status()}): ${errorText}`);
126
+ }
127
+
128
+ const data = await response.json();
129
+ return {
130
+ slug: data.article.slug,
131
+ title: data.article.title,
132
+ };
133
+ } catch (error) {
134
+ throw new Error(`Failed to create article via API: ${error}`);
135
+ }
136
+ }
137
+
138
+ /**
139
+ * Delete an article via API
140
+ */
141
+ export async function deleteArticleViaAPI(
142
+ request: APIRequestContext,
143
+ token: string,
144
+ slug: string
145
+ ): Promise<void> {
146
+ const config = getAPIConfig();
147
+
148
+ try {
149
+ const response = await request.delete(`${config.baseURL}/articles/${slug}`, {
150
+ headers: {
151
+ 'Authorization': `Token ${token}`,
152
+ },
153
+ });
154
+
155
+ if (!response.ok()) {
156
+ const errorText = await response.text();
157
+ throw new Error(`API article deletion failed (${response.status()}): ${errorText}`);
158
+ }
159
+ } catch (error) {
160
+ throw new Error(`Failed to delete article via API: ${error}`);
161
+ }
162
+ }
163
+
164
+ /**
165
+ * Update user via API
166
+ */
167
+ export async function updateUserViaAPI(
168
+ request: APIRequestContext,
169
+ token: string,
170
+ updates: {
171
+ email?: string;
172
+ bio?: string;
173
+ image?: string;
174
+ username?: string;
175
+ password?: string;
176
+ }
177
+ ): Promise<void> {
178
+ const config = getAPIConfig();
179
+
180
+ try {
181
+ const response = await request.put(`${config.baseURL}/user`, {
182
+ data: { user: updates },
183
+ headers: {
184
+ 'Content-Type': 'application/json',
185
+ 'Authorization': `Token ${token}`,
186
+ },
187
+ });
188
+
189
+ if (!response.ok()) {
190
+ const errorText = await response.text();
191
+ throw new Error(`API user update failed (${response.status()}): ${errorText}`);
192
+ }
193
+ } catch (error) {
194
+ throw new Error(`Failed to update user via API: ${error}`);
195
+ }
196
+ }
197
+
198
+ /**
199
+ * Get current user via API
200
+ */
201
+ export async function getCurrentUserViaAPI(
202
+ request: APIRequestContext,
203
+ token: string
204
+ ): Promise<APIAuthResponse['user']> {
205
+ const config = getAPIConfig();
206
+
207
+ try {
208
+ const response = await request.get(`${config.baseURL}/user`, {
209
+ headers: {
210
+ 'Authorization': `Token ${token}`,
211
+ },
212
+ });
213
+
214
+ if (!response.ok()) {
215
+ const errorText = await response.text();
216
+ throw new Error(`API get user failed (${response.status()}): ${errorText}`);
217
+ }
218
+
219
+ const data = await response.json();
220
+ return data.user;
221
+ } catch (error) {
222
+ throw new Error(`Failed to get current user via API: ${error}`);
223
+ }
224
+ }
@@ -0,0 +1,35 @@
1
+ import { Page } from '@playwright/test';
2
+ export interface UserCredentials {
3
+ username: string;
4
+ email: string;
5
+ password: string;
6
+ }
7
+ export interface AuthResult {
8
+ success: boolean;
9
+ error?: string;
10
+ }
11
+ /**
12
+ * Register a new user via UI
13
+ */
14
+ export declare function register(page: Page, username: string, email: string, password: string): Promise<AuthResult>;
15
+ /**
16
+ * Login a user via UI
17
+ */
18
+ export declare function login(page: Page, email: string, password: string): Promise<AuthResult>;
19
+ /**
20
+ * Logout a user via UI
21
+ */
22
+ export declare function logout(page: Page): Promise<void>;
23
+ /**
24
+ * Generate unique user credentials to avoid conflicts
25
+ */
26
+ export declare function generateUniqueUser(): UserCredentials;
27
+ /**
28
+ * Check if user is logged in
29
+ */
30
+ export declare function isLoggedIn(page: Page): Promise<boolean>;
31
+ /**
32
+ * Get current username if logged in
33
+ */
34
+ export declare function getCurrentUsername(page: Page): Promise<string | null>;
35
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,UAAU,CAAC,CAmBrB;AAED;;GAEG;AACH,wBAAsB,KAAK,CACzB,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,UAAU,CAAC,CAkBrB;AAED;;GAEG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBtD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,eAAe,CAQpD;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAM7D;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAM3E"}
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.register = register;
4
+ exports.login = login;
5
+ exports.logout = logout;
6
+ exports.generateUniqueUser = generateUniqueUser;
7
+ exports.isLoggedIn = isLoggedIn;
8
+ exports.getCurrentUsername = getCurrentUsername;
9
+ /**
10
+ * Register a new user via UI
11
+ */
12
+ async function register(page, username, email, password) {
13
+ await page.goto('/register', { waitUntil: 'networkidle' });
14
+ await page.fill('input[name="username"]', username);
15
+ await page.fill('input[name="email"]', email);
16
+ await page.fill('input[name="password"]', password);
17
+ try {
18
+ await Promise.all([
19
+ page.waitForURL('/', { timeout: 10000 }),
20
+ page.click('button[type="submit"]')
21
+ ]);
22
+ return { success: true };
23
+ }
24
+ catch (error) {
25
+ const errorMsg = await page.locator('.error-messages, [data-testid="error-message"]').textContent().catch(() => '');
26
+ if (errorMsg) {
27
+ return { success: false, error: `Registration failed: ${errorMsg.trim()}` };
28
+ }
29
+ return { success: false, error: `Registration failed: ${error}` };
30
+ }
31
+ }
32
+ /**
33
+ * Login a user via UI
34
+ */
35
+ async function login(page, email, password) {
36
+ await page.goto('/login', { waitUntil: 'networkidle' });
37
+ await page.fill('input[name="email"]', email);
38
+ await page.fill('input[name="password"]', password);
39
+ try {
40
+ await Promise.all([
41
+ page.waitForURL('/', { timeout: 10000 }),
42
+ page.click('button[type="submit"]')
43
+ ]);
44
+ return { success: true };
45
+ }
46
+ catch (error) {
47
+ const errorMsg = await page.locator('.error-messages, [data-testid="error-message"]').textContent().catch(() => '');
48
+ if (errorMsg) {
49
+ return { success: false, error: `Login failed: ${errorMsg.trim()}` };
50
+ }
51
+ return { success: false, error: `Login failed: ${error}` };
52
+ }
53
+ }
54
+ /**
55
+ * Logout a user via UI
56
+ */
57
+ async function logout(page) {
58
+ // Try different logout patterns
59
+ const settingsLink = page.locator('a[href="/settings"], a:has-text("Settings"), [data-testid="settings-link"]').first();
60
+ if (await settingsLink.isVisible().catch(() => false)) {
61
+ await settingsLink.click();
62
+ await page.waitForURL('/settings', { timeout: 5000 });
63
+ }
64
+ else {
65
+ await page.goto('/settings');
66
+ }
67
+ const logoutButton = page.locator('button:has-text("logout"), button:has-text("Logout"), [data-testid="logout-button"]').first();
68
+ await Promise.all([
69
+ page.waitForURL('/', { timeout: 10000 }),
70
+ logoutButton.click()
71
+ ]);
72
+ }
73
+ /**
74
+ * Generate unique user credentials to avoid conflicts
75
+ */
76
+ function generateUniqueUser() {
77
+ const timestamp = Date.now();
78
+ const random = Math.random().toString(36).substring(2, 8);
79
+ return {
80
+ username: `testuser_${timestamp}_${random}`,
81
+ email: `test_${timestamp}_${random}@example.com`,
82
+ password: 'TestPassword123!',
83
+ };
84
+ }
85
+ /**
86
+ * Check if user is logged in
87
+ */
88
+ async function isLoggedIn(page) {
89
+ // Check for logout button or user-specific elements
90
+ const logoutVisible = await page.locator('a[href="/settings"], [data-testid="logout-button"]').isVisible().catch(() => false);
91
+ const loginVisible = await page.locator('a[href="/login"]').isVisible().catch(() => false);
92
+ return logoutVisible && !loginVisible;
93
+ }
94
+ /**
95
+ * Get current username if logged in
96
+ */
97
+ async function getCurrentUsername(page) {
98
+ const usernameElement = page.locator('[data-testid="username"], .user-name, .username').first();
99
+ if (await usernameElement.isVisible().catch(() => false)) {
100
+ return usernameElement.textContent();
101
+ }
102
+ return null;
103
+ }
104
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["auth.ts"],"names":[],"mappings":"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"}