@growsober/sdk 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.
- package/README.md +276 -0
- package/dist/__tests__/e2e.test.d.ts +7 -0
- package/dist/__tests__/e2e.test.js +472 -0
- package/dist/api/client.d.ts +11 -0
- package/dist/api/client.js +61 -0
- package/dist/api/mutations/admin.d.ts +167 -0
- package/dist/api/mutations/admin.js +326 -0
- package/dist/api/mutations/ambassadors.d.ts +52 -0
- package/dist/api/mutations/ambassadors.js +148 -0
- package/dist/api/mutations/auth.d.ts +267 -0
- package/dist/api/mutations/auth.js +332 -0
- package/dist/api/mutations/bookings.d.ts +59 -0
- package/dist/api/mutations/bookings.js +143 -0
- package/dist/api/mutations/event-chat.d.ts +35 -0
- package/dist/api/mutations/event-chat.js +147 -0
- package/dist/api/mutations/events.d.ts +87 -0
- package/dist/api/mutations/events.js +205 -0
- package/dist/api/mutations/grow90.d.ts +36 -0
- package/dist/api/mutations/grow90.js +132 -0
- package/dist/api/mutations/hubs.d.ts +111 -0
- package/dist/api/mutations/hubs.js +240 -0
- package/dist/api/mutations/index.d.ts +22 -0
- package/dist/api/mutations/index.js +39 -0
- package/dist/api/mutations/jack.d.ts +61 -0
- package/dist/api/mutations/jack.js +104 -0
- package/dist/api/mutations/library.d.ts +67 -0
- package/dist/api/mutations/library.js +168 -0
- package/dist/api/mutations/map.d.ts +153 -0
- package/dist/api/mutations/map.js +181 -0
- package/dist/api/mutations/matching.d.ts +130 -0
- package/dist/api/mutations/matching.js +204 -0
- package/dist/api/mutations/notifications.d.ts +63 -0
- package/dist/api/mutations/notifications.js +106 -0
- package/dist/api/mutations/offers.d.ts +26 -0
- package/dist/api/mutations/offers.js +47 -0
- package/dist/api/mutations/subscriptions.d.ts +127 -0
- package/dist/api/mutations/subscriptions.js +140 -0
- package/dist/api/mutations/support.d.ts +165 -0
- package/dist/api/mutations/support.js +307 -0
- package/dist/api/mutations/users.d.ts +211 -0
- package/dist/api/mutations/users.js +261 -0
- package/dist/api/queries/admin.d.ts +257 -0
- package/dist/api/queries/admin.js +320 -0
- package/dist/api/queries/ambassadors.d.ts +53 -0
- package/dist/api/queries/ambassadors.js +98 -0
- package/dist/api/queries/auth.d.ts +16 -0
- package/dist/api/queries/auth.js +25 -0
- package/dist/api/queries/bookings.d.ts +91 -0
- package/dist/api/queries/bookings.js +102 -0
- package/dist/api/queries/businesses.d.ts +212 -0
- package/dist/api/queries/businesses.js +154 -0
- package/dist/api/queries/event-chat.d.ts +19 -0
- package/dist/api/queries/event-chat.js +75 -0
- package/dist/api/queries/events.d.ts +322 -0
- package/dist/api/queries/events.js +221 -0
- package/dist/api/queries/grow90.d.ts +26 -0
- package/dist/api/queries/grow90.js +85 -0
- package/dist/api/queries/hubs.d.ts +165 -0
- package/dist/api/queries/hubs.js +143 -0
- package/dist/api/queries/index.d.ts +23 -0
- package/dist/api/queries/index.js +40 -0
- package/dist/api/queries/jack.d.ts +63 -0
- package/dist/api/queries/jack.js +92 -0
- package/dist/api/queries/library.d.ts +132 -0
- package/dist/api/queries/library.js +120 -0
- package/dist/api/queries/map.d.ts +216 -0
- package/dist/api/queries/map.js +278 -0
- package/dist/api/queries/matching.d.ts +136 -0
- package/dist/api/queries/matching.js +161 -0
- package/dist/api/queries/notifications.d.ts +78 -0
- package/dist/api/queries/notifications.js +88 -0
- package/dist/api/queries/offers.d.ts +91 -0
- package/dist/api/queries/offers.js +103 -0
- package/dist/api/queries/subscriptions.d.ts +56 -0
- package/dist/api/queries/subscriptions.js +73 -0
- package/dist/api/queries/support.d.ts +106 -0
- package/dist/api/queries/support.js +202 -0
- package/dist/api/queries/users.d.ts +293 -0
- package/dist/api/queries/users.js +370 -0
- package/dist/api/types.d.ts +464 -0
- package/dist/api/types.js +9 -0
- package/dist/hooks/useAuth.d.ts +5 -0
- package/dist/hooks/useAuth.js +39 -0
- package/dist/hooks/useUser.d.ts +43 -0
- package/dist/hooks/useUser.js +44 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +67 -0
- package/package.json +62 -0
- package/src/__tests__/e2e.test.ts +502 -0
- package/src/api/client.ts +71 -0
- package/src/api/mutations/admin.ts +531 -0
- package/src/api/mutations/ambassadors.ts +185 -0
- package/src/api/mutations/auth.ts +350 -0
- package/src/api/mutations/bookings.ts +190 -0
- package/src/api/mutations/event-chat.ts +177 -0
- package/src/api/mutations/events.ts +273 -0
- package/src/api/mutations/grow90.ts +169 -0
- package/src/api/mutations/hubs.ts +385 -0
- package/src/api/mutations/index.ts +23 -0
- package/src/api/mutations/jack.ts +130 -0
- package/src/api/mutations/library.ts +212 -0
- package/src/api/mutations/map.ts +230 -0
- package/src/api/mutations/matching.ts +271 -0
- package/src/api/mutations/notifications.ts +114 -0
- package/src/api/mutations/offers.ts +73 -0
- package/src/api/mutations/subscriptions.ts +162 -0
- package/src/api/mutations/support.ts +390 -0
- package/src/api/mutations/users.ts +271 -0
- package/src/api/queries/admin.ts +480 -0
- package/src/api/queries/ambassadors.ts +139 -0
- package/src/api/queries/auth.ts +24 -0
- package/src/api/queries/bookings.ts +135 -0
- package/src/api/queries/businesses.ts +203 -0
- package/src/api/queries/event-chat.ts +78 -0
- package/src/api/queries/events.ts +272 -0
- package/src/api/queries/grow90.ts +98 -0
- package/src/api/queries/hubs.ts +211 -0
- package/src/api/queries/index.ts +24 -0
- package/src/api/queries/jack.ts +127 -0
- package/src/api/queries/library.ts +166 -0
- package/src/api/queries/map.ts +331 -0
- package/src/api/queries/matching.ts +238 -0
- package/src/api/queries/notifications.ts +103 -0
- package/src/api/queries/offers.ts +136 -0
- package/src/api/queries/subscriptions.ts +91 -0
- package/src/api/queries/support.ts +235 -0
- package/src/api/queries/users.ts +393 -0
- package/src/api/types.ts +596 -0
- package/src/index.ts +57 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GrowSober SDK
|
|
3
|
+
*
|
|
4
|
+
* TypeScript SDK for the GrowSober API with TanStack Query hooks.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* import { configureSDK, useCurrentUser, useLogin } from '@growsober/sdk';
|
|
9
|
+
*
|
|
10
|
+
* // Configure SDK with your API base URL and token management
|
|
11
|
+
* configureSDK({
|
|
12
|
+
* baseURL: 'https://api.growsober.app',
|
|
13
|
+
* getAccessToken: () => localStorage.getItem('accessToken'),
|
|
14
|
+
* refreshAccessToken: async () => {
|
|
15
|
+
* // Your token refresh logic
|
|
16
|
+
* return newAccessToken;
|
|
17
|
+
* },
|
|
18
|
+
* onUnauthorized: () => {
|
|
19
|
+
* // Handle unauthorized access
|
|
20
|
+
* window.location.href = '/login';
|
|
21
|
+
* },
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* // Use hooks in your components
|
|
25
|
+
* function App() {
|
|
26
|
+
* const { data: user } = useCurrentUser();
|
|
27
|
+
* const { mutate: login } = useLogin();
|
|
28
|
+
* // ...
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export { configureSDK, getApiClient } from './api/client';
|
|
33
|
+
export type { SDKConfig } from './api/client';
|
|
34
|
+
export * from './api/types';
|
|
35
|
+
export * from './api/queries';
|
|
36
|
+
export * from './api/mutations';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* GrowSober SDK
|
|
4
|
+
*
|
|
5
|
+
* TypeScript SDK for the GrowSober API with TanStack Query hooks.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* import { configureSDK, useCurrentUser, useLogin } from '@growsober/sdk';
|
|
10
|
+
*
|
|
11
|
+
* // Configure SDK with your API base URL and token management
|
|
12
|
+
* configureSDK({
|
|
13
|
+
* baseURL: 'https://api.growsober.app',
|
|
14
|
+
* getAccessToken: () => localStorage.getItem('accessToken'),
|
|
15
|
+
* refreshAccessToken: async () => {
|
|
16
|
+
* // Your token refresh logic
|
|
17
|
+
* return newAccessToken;
|
|
18
|
+
* },
|
|
19
|
+
* onUnauthorized: () => {
|
|
20
|
+
* // Handle unauthorized access
|
|
21
|
+
* window.location.href = '/login';
|
|
22
|
+
* },
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* // Use hooks in your components
|
|
26
|
+
* function App() {
|
|
27
|
+
* const { data: user } = useCurrentUser();
|
|
28
|
+
* const { mutate: login } = useLogin();
|
|
29
|
+
* // ...
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
34
|
+
if (k2 === undefined) k2 = k;
|
|
35
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
36
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
37
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
38
|
+
}
|
|
39
|
+
Object.defineProperty(o, k2, desc);
|
|
40
|
+
}) : (function(o, m, k, k2) {
|
|
41
|
+
if (k2 === undefined) k2 = k;
|
|
42
|
+
o[k2] = m[k];
|
|
43
|
+
}));
|
|
44
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
45
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
46
|
+
};
|
|
47
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
+
exports.getApiClient = exports.configureSDK = void 0;
|
|
49
|
+
// ============================================================================
|
|
50
|
+
// API CLIENT
|
|
51
|
+
// ============================================================================
|
|
52
|
+
var client_1 = require("./api/client");
|
|
53
|
+
Object.defineProperty(exports, "configureSDK", { enumerable: true, get: function () { return client_1.configureSDK; } });
|
|
54
|
+
Object.defineProperty(exports, "getApiClient", { enumerable: true, get: function () { return client_1.getApiClient; } });
|
|
55
|
+
// ============================================================================
|
|
56
|
+
// TYPES
|
|
57
|
+
// ============================================================================
|
|
58
|
+
__exportStar(require("./api/types"), exports);
|
|
59
|
+
// ============================================================================
|
|
60
|
+
// QUERY HOOKS
|
|
61
|
+
// ============================================================================
|
|
62
|
+
__exportStar(require("./api/queries"), exports);
|
|
63
|
+
// ============================================================================
|
|
64
|
+
// MUTATION HOOKS
|
|
65
|
+
// ============================================================================
|
|
66
|
+
__exportStar(require("./api/mutations"), exports);
|
|
67
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0E4Qkc7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBRUgsK0VBQStFO0FBQy9FLGFBQWE7QUFDYiwrRUFBK0U7QUFFL0UsdUNBQTBEO0FBQWpELHNHQUFBLFlBQVksT0FBQTtBQUFFLHNHQUFBLFlBQVksT0FBQTtBQUduQywrRUFBK0U7QUFDL0UsUUFBUTtBQUNSLCtFQUErRTtBQUUvRSw4Q0FBNEI7QUFFNUIsK0VBQStFO0FBQy9FLGNBQWM7QUFDZCwrRUFBK0U7QUFFL0UsZ0RBQThCO0FBRTlCLCtFQUErRTtBQUMvRSxpQkFBaUI7QUFDakIsK0VBQStFO0FBRS9FLGtEQUFnQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogR3Jvd1NvYmVyIFNES1xuICpcbiAqIFR5cGVTY3JpcHQgU0RLIGZvciB0aGUgR3Jvd1NvYmVyIEFQSSB3aXRoIFRhblN0YWNrIFF1ZXJ5IGhvb2tzLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0c3hcbiAqIGltcG9ydCB7IGNvbmZpZ3VyZVNESywgdXNlQ3VycmVudFVzZXIsIHVzZUxvZ2luIH0gZnJvbSAnQGdyb3dzb2Jlci9zZGsnO1xuICpcbiAqIC8vIENvbmZpZ3VyZSBTREsgd2l0aCB5b3VyIEFQSSBiYXNlIFVSTCBhbmQgdG9rZW4gbWFuYWdlbWVudFxuICogY29uZmlndXJlU0RLKHtcbiAqICAgYmFzZVVSTDogJ2h0dHBzOi8vYXBpLmdyb3dzb2Jlci5hcHAnLFxuICogICBnZXRBY2Nlc3NUb2tlbjogKCkgPT4gbG9jYWxTdG9yYWdlLmdldEl0ZW0oJ2FjY2Vzc1Rva2VuJyksXG4gKiAgIHJlZnJlc2hBY2Nlc3NUb2tlbjogYXN5bmMgKCkgPT4ge1xuICogICAgIC8vIFlvdXIgdG9rZW4gcmVmcmVzaCBsb2dpY1xuICogICAgIHJldHVybiBuZXdBY2Nlc3NUb2tlbjtcbiAqICAgfSxcbiAqICAgb25VbmF1dGhvcml6ZWQ6ICgpID0+IHtcbiAqICAgICAvLyBIYW5kbGUgdW5hdXRob3JpemVkIGFjY2Vzc1xuICogICAgIHdpbmRvdy5sb2NhdGlvbi5ocmVmID0gJy9sb2dpbic7XG4gKiAgIH0sXG4gKiB9KTtcbiAqXG4gKiAvLyBVc2UgaG9va3MgaW4geW91ciBjb21wb25lbnRzXG4gKiBmdW5jdGlvbiBBcHAoKSB7XG4gKiAgIGNvbnN0IHsgZGF0YTogdXNlciB9ID0gdXNlQ3VycmVudFVzZXIoKTtcbiAqICAgY29uc3QgeyBtdXRhdGU6IGxvZ2luIH0gPSB1c2VMb2dpbigpO1xuICogICAvLyAuLi5cbiAqIH1cbiAqIGBgYFxuICovXG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIEFQSSBDTElFTlRcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuZXhwb3J0IHsgY29uZmlndXJlU0RLLCBnZXRBcGlDbGllbnQgfSBmcm9tICcuL2FwaS9jbGllbnQnO1xuZXhwb3J0IHR5cGUgeyBTREtDb25maWcgfSBmcm9tICcuL2FwaS9jbGllbnQnO1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBUWVBFU1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5leHBvcnQgKiBmcm9tICcuL2FwaS90eXBlcyc7XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIFFVRVJZIEhPT0tTXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbmV4cG9ydCAqIGZyb20gJy4vYXBpL3F1ZXJpZXMnO1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBNVVRBVElPTiBIT09LU1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5leHBvcnQgKiBmcm9tICcuL2FwaS9tdXRhdGlvbnMnO1xuXG4iXX0=
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@growsober/sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Shared TypeScript SDK for GrowSober API - TanStack Query hooks, API client, and utilities",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.js",
|
|
7
|
+
"source": "src/index.ts",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"react-native": "src/index.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"require": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"src"
|
|
20
|
+
],
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "https://github.com/souldevsoul/growsober-sdk.git"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"build": "tsc",
|
|
30
|
+
"build:watch": "tsc --watch",
|
|
31
|
+
"type-check": "tsc --noEmit",
|
|
32
|
+
"lint": "eslint src --ext .ts",
|
|
33
|
+
"prepublishOnly": "npm run build",
|
|
34
|
+
"test:e2e": "npx ts-node src/__tests__/e2e.test.ts"
|
|
35
|
+
},
|
|
36
|
+
"keywords": [
|
|
37
|
+
"growsober",
|
|
38
|
+
"api",
|
|
39
|
+
"sdk",
|
|
40
|
+
"tanstack-query",
|
|
41
|
+
"react-query",
|
|
42
|
+
"typescript"
|
|
43
|
+
],
|
|
44
|
+
"author": "SoulToSoul",
|
|
45
|
+
"license": "MIT",
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"@tanstack/react-query": "^5.0.0",
|
|
48
|
+
"axios": "^1.6.0",
|
|
49
|
+
"react": ">=18.0.0",
|
|
50
|
+
"zod": "^3.0.0"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@growsober/types": "^1.0.0"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@types/node": "^20.0.0",
|
|
57
|
+
"@types/react": "^18.0.0",
|
|
58
|
+
"axios": "^1.13.2",
|
|
59
|
+
"ts-node": "^10.9.0",
|
|
60
|
+
"typescript": "^5.9.3"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GrowSober API E2E Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests all SDK endpoints against the real API.
|
|
5
|
+
* Run with: npx ts-node src/__tests__/e2e.test.ts
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import axios, { AxiosInstance } from 'axios';
|
|
9
|
+
|
|
10
|
+
const BASE_URL = 'http://localhost:3001/api/v1';
|
|
11
|
+
const TEST_EMAIL = `e2e-${Date.now()}@growsober.com`;
|
|
12
|
+
const TEST_PASSWORD = 'SecurePass123!';
|
|
13
|
+
|
|
14
|
+
// Colors for output
|
|
15
|
+
const c = {
|
|
16
|
+
reset: '\x1b[0m',
|
|
17
|
+
green: '\x1b[32m',
|
|
18
|
+
red: '\x1b[31m',
|
|
19
|
+
yellow: '\x1b[33m',
|
|
20
|
+
cyan: '\x1b[36m',
|
|
21
|
+
dim: '\x1b[2m',
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// State shared across tests
|
|
25
|
+
const state: {
|
|
26
|
+
accessToken: string;
|
|
27
|
+
refreshToken: string;
|
|
28
|
+
userId: string;
|
|
29
|
+
eventId?: string;
|
|
30
|
+
hubId?: string;
|
|
31
|
+
bookingId?: string;
|
|
32
|
+
chatId?: string;
|
|
33
|
+
conversationId?: string;
|
|
34
|
+
} = {
|
|
35
|
+
accessToken: '',
|
|
36
|
+
refreshToken: '',
|
|
37
|
+
userId: '',
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// Stats
|
|
41
|
+
let passed = 0;
|
|
42
|
+
let failed = 0;
|
|
43
|
+
|
|
44
|
+
// Create axios client
|
|
45
|
+
function api(token?: string): AxiosInstance {
|
|
46
|
+
return axios.create({
|
|
47
|
+
baseURL: BASE_URL,
|
|
48
|
+
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
|
49
|
+
validateStatus: () => true,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Test runner
|
|
54
|
+
async function test(name: string, fn: () => Promise<void>): Promise<boolean> {
|
|
55
|
+
const start = Date.now();
|
|
56
|
+
try {
|
|
57
|
+
await fn();
|
|
58
|
+
console.log(`${c.green}PASS${c.reset} ${name} ${c.dim}(${Date.now() - start}ms)${c.reset}`);
|
|
59
|
+
passed++;
|
|
60
|
+
return true;
|
|
61
|
+
} catch (e: any) {
|
|
62
|
+
console.log(`${c.red}FAIL${c.reset} ${name} ${c.dim}(${Date.now() - start}ms)${c.reset}`);
|
|
63
|
+
console.log(` ${c.yellow}${e.message}${c.reset}`);
|
|
64
|
+
failed++;
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Unwrap API response
|
|
70
|
+
function unwrap<T>(res: { data: { data: T } }): T {
|
|
71
|
+
return res.data.data;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ============================================================================
|
|
75
|
+
// TESTS
|
|
76
|
+
// ============================================================================
|
|
77
|
+
|
|
78
|
+
async function runTests() {
|
|
79
|
+
console.log(`\n${c.cyan}${'='.repeat(60)}${c.reset}`);
|
|
80
|
+
console.log(`${c.cyan} GrowSober API E2E Tests${c.reset}`);
|
|
81
|
+
console.log(`${c.cyan}${'='.repeat(60)}${c.reset}`);
|
|
82
|
+
console.log(`${c.dim}Base URL: ${BASE_URL}${c.reset}`);
|
|
83
|
+
console.log(`${c.dim}Test Email: ${TEST_EMAIL}${c.reset}\n`);
|
|
84
|
+
|
|
85
|
+
// Health check
|
|
86
|
+
const health = await api().get('/health');
|
|
87
|
+
if (health.status !== 200) {
|
|
88
|
+
console.log(`${c.red}API is not reachable${c.reset}`);
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
console.log(`${c.green}API is healthy${c.reset}\n`);
|
|
92
|
+
|
|
93
|
+
// =========================================================================
|
|
94
|
+
// AUTH
|
|
95
|
+
// =========================================================================
|
|
96
|
+
console.log(`\n${c.cyan}--- AUTHENTICATION ---${c.reset}\n`);
|
|
97
|
+
|
|
98
|
+
await test('Register new user', async () => {
|
|
99
|
+
const res = await api().post('/auth/register', {
|
|
100
|
+
email: TEST_EMAIL,
|
|
101
|
+
password: TEST_PASSWORD,
|
|
102
|
+
name: 'E2E Test User',
|
|
103
|
+
});
|
|
104
|
+
if (res.status !== 201) throw new Error(`Status ${res.status}: ${JSON.stringify(res.data)}`);
|
|
105
|
+
const data = unwrap<any>(res);
|
|
106
|
+
state.accessToken = data.accessToken;
|
|
107
|
+
state.refreshToken = data.refreshToken;
|
|
108
|
+
state.userId = data.user.id;
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
await test('Login with email', async () => {
|
|
112
|
+
const res = await api().post('/auth/login', {
|
|
113
|
+
email: TEST_EMAIL,
|
|
114
|
+
password: TEST_PASSWORD,
|
|
115
|
+
});
|
|
116
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
117
|
+
const data = unwrap<any>(res);
|
|
118
|
+
state.accessToken = data.accessToken;
|
|
119
|
+
state.refreshToken = data.refreshToken;
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
await test('Refresh token', async () => {
|
|
123
|
+
const res = await api().post('/auth/refresh', {
|
|
124
|
+
refreshToken: state.refreshToken,
|
|
125
|
+
});
|
|
126
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}: ${JSON.stringify(res.data)}`);
|
|
127
|
+
const data = unwrap<any>(res);
|
|
128
|
+
state.accessToken = data.accessToken;
|
|
129
|
+
state.refreshToken = data.refreshToken;
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
await test('Get current user (auth/me)', async () => {
|
|
133
|
+
const res = await api(state.accessToken).get('/auth/me');
|
|
134
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
await test('Invalid login returns 401', async () => {
|
|
138
|
+
const res = await api().post('/auth/login', {
|
|
139
|
+
email: TEST_EMAIL,
|
|
140
|
+
password: 'WrongPassword',
|
|
141
|
+
});
|
|
142
|
+
if (res.status !== 401) throw new Error(`Expected 401, got ${res.status}`);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// =========================================================================
|
|
146
|
+
// USERS
|
|
147
|
+
// =========================================================================
|
|
148
|
+
console.log(`\n${c.cyan}--- USERS ---${c.reset}\n`);
|
|
149
|
+
|
|
150
|
+
await test('Get current user profile', async () => {
|
|
151
|
+
const res = await api(state.accessToken).get('/users/me');
|
|
152
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
await test('Update profile', async () => {
|
|
156
|
+
const res = await api(state.accessToken).put('/users/me', {
|
|
157
|
+
name: 'Updated E2E User',
|
|
158
|
+
bio: 'E2E test bio',
|
|
159
|
+
});
|
|
160
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}: ${JSON.stringify(res.data)}`);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
await test('Get user by ID', async () => {
|
|
164
|
+
const res = await api(state.accessToken).get(`/users/${state.userId}`);
|
|
165
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
await test('Get user public profile', async () => {
|
|
169
|
+
const res = await api(state.accessToken).get(`/users/${state.userId}/public`);
|
|
170
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// =========================================================================
|
|
174
|
+
// EVENTS
|
|
175
|
+
// =========================================================================
|
|
176
|
+
console.log(`\n${c.cyan}--- EVENTS ---${c.reset}\n`);
|
|
177
|
+
|
|
178
|
+
await test('List events', async () => {
|
|
179
|
+
const res = await api().get('/events');
|
|
180
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
await test('Get upcoming events', async () => {
|
|
184
|
+
const res = await api().get('/events/upcoming');
|
|
185
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
await test('Create event', async () => {
|
|
189
|
+
const res = await api(state.accessToken).post('/events', {
|
|
190
|
+
title: 'E2E Test Event',
|
|
191
|
+
description: 'A test event created by E2E tests',
|
|
192
|
+
startDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(), // 7 days from now
|
|
193
|
+
totalSpots: 20,
|
|
194
|
+
locationName: 'Test Location',
|
|
195
|
+
locationAddress: '123 Test Street',
|
|
196
|
+
});
|
|
197
|
+
if (res.status !== 201) throw new Error(`Status ${res.status}: ${JSON.stringify(res.data)}`);
|
|
198
|
+
const data = unwrap<any>(res);
|
|
199
|
+
state.eventId = data.id;
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
if (state.eventId) {
|
|
203
|
+
await test('Get event by ID', async () => {
|
|
204
|
+
const res = await api().get(`/events/${state.eventId}`);
|
|
205
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
await test('Update event', async () => {
|
|
209
|
+
const res = await api(state.accessToken).put(`/events/${state.eventId}`, {
|
|
210
|
+
title: 'E2E Test Event (Updated)',
|
|
211
|
+
});
|
|
212
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}: ${JSON.stringify(res.data)}`);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
await test('Publish event', async () => {
|
|
216
|
+
const res = await api(state.accessToken).post(`/events/${state.eventId}/publish`);
|
|
217
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
await test('Get my events', async () => {
|
|
221
|
+
const res = await api(state.accessToken).get('/events/my-events');
|
|
222
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// =========================================================================
|
|
227
|
+
// BOOKINGS
|
|
228
|
+
// =========================================================================
|
|
229
|
+
console.log(`\n${c.cyan}--- BOOKINGS ---${c.reset}\n`);
|
|
230
|
+
|
|
231
|
+
if (state.eventId) {
|
|
232
|
+
await test('RSVP to event', async () => {
|
|
233
|
+
const res = await api(state.accessToken).post(`/events/${state.eventId}/book`);
|
|
234
|
+
// 201 for new booking, 409 if already exists
|
|
235
|
+
if (res.status !== 201 && res.status !== 409) throw new Error(`Status ${res.status}: ${JSON.stringify(res.data)}`);
|
|
236
|
+
if (res.status === 201) {
|
|
237
|
+
const data = unwrap<any>(res);
|
|
238
|
+
state.bookingId = data.id;
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
await test('Get my bookings', async () => {
|
|
243
|
+
const res = await api(state.accessToken).get('/bookings/me');
|
|
244
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// =========================================================================
|
|
249
|
+
// EVENT CHAT
|
|
250
|
+
// =========================================================================
|
|
251
|
+
console.log(`\n${c.cyan}--- EVENT CHAT ---${c.reset}\n`);
|
|
252
|
+
|
|
253
|
+
if (state.eventId) {
|
|
254
|
+
await test('Get or create event chat', async () => {
|
|
255
|
+
const res = await api(state.accessToken).get(`/events/${state.eventId}/chat`);
|
|
256
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}: ${JSON.stringify(res.data)}`);
|
|
257
|
+
const data = unwrap<any>(res);
|
|
258
|
+
state.chatId = data.id;
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
await test('Join event chat', async () => {
|
|
262
|
+
const res = await api(state.accessToken).post(`/events/${state.eventId}/chat/join`);
|
|
263
|
+
// 200 for join, 403 if no booking (but we just booked)
|
|
264
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}: ${JSON.stringify(res.data)}`);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
await test('Send chat message', async () => {
|
|
268
|
+
const res = await api(state.accessToken).post(`/events/${state.eventId}/chat/messages`, {
|
|
269
|
+
content: 'Hello from E2E test!',
|
|
270
|
+
});
|
|
271
|
+
if (res.status !== 201) throw new Error(`Status ${res.status}: ${JSON.stringify(res.data)}`);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
await test('Get chat messages', async () => {
|
|
275
|
+
const res = await api(state.accessToken).get(`/events/${state.eventId}/chat/messages`);
|
|
276
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}: ${JSON.stringify(res.data)}`);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
await test('Get chat members', async () => {
|
|
280
|
+
const res = await api(state.accessToken).get(`/events/${state.eventId}/chat/members`);
|
|
281
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
await test('Mark chat as read', async () => {
|
|
285
|
+
const res = await api(state.accessToken).post(`/events/${state.eventId}/chat/read`);
|
|
286
|
+
if (res.status !== 204) throw new Error(`Status ${res.status}`);
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// =========================================================================
|
|
291
|
+
// HUBS
|
|
292
|
+
// =========================================================================
|
|
293
|
+
console.log(`\n${c.cyan}--- HUBS ---${c.reset}\n`);
|
|
294
|
+
|
|
295
|
+
await test('List hubs', async () => {
|
|
296
|
+
const res = await api().get('/hubs');
|
|
297
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
298
|
+
// Get first hub if exists
|
|
299
|
+
const data = res.data.data;
|
|
300
|
+
if (Array.isArray(data) && data.length > 0) {
|
|
301
|
+
state.hubId = data[0].id;
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
if (state.hubId) {
|
|
306
|
+
await test('Get hub by ID', async () => {
|
|
307
|
+
const res = await api().get(`/hubs/${state.hubId}`);
|
|
308
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
await test('Join hub', async () => {
|
|
312
|
+
const res = await api(state.accessToken).post(`/hubs/${state.hubId}/join`);
|
|
313
|
+
// 200/201 for join, 409 if already member
|
|
314
|
+
if (res.status !== 200 && res.status !== 201 && res.status !== 409) {
|
|
315
|
+
throw new Error(`Status ${res.status}: ${JSON.stringify(res.data)}`);
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
await test('Get hub members', async () => {
|
|
320
|
+
const res = await api(state.accessToken).get(`/hubs/${state.hubId}/members`);
|
|
321
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// =========================================================================
|
|
326
|
+
// JACK AI (Support Conversations)
|
|
327
|
+
// =========================================================================
|
|
328
|
+
console.log(`\n${c.cyan}--- JACK AI ---${c.reset}\n`);
|
|
329
|
+
|
|
330
|
+
await test('Start Jack conversation', async () => {
|
|
331
|
+
const res = await api(state.accessToken).post('/support/jack/conversations/new', {
|
|
332
|
+
message: 'Hello Jack!',
|
|
333
|
+
});
|
|
334
|
+
if (res.status !== 201 && res.status !== 200) throw new Error(`Status ${res.status}: ${JSON.stringify(res.data)}`);
|
|
335
|
+
const data = unwrap<any>(res);
|
|
336
|
+
state.conversationId = data.conversation?.id || data.id;
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
await test('Get Jack conversations', async () => {
|
|
340
|
+
const res = await api(state.accessToken).get('/support/jack/conversations');
|
|
341
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
await test('Get Jack chat history', async () => {
|
|
345
|
+
const res = await api(state.accessToken).get('/support/jack/history');
|
|
346
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
if (state.conversationId) {
|
|
350
|
+
await test('Get Jack conversation by ID', async () => {
|
|
351
|
+
const res = await api(state.accessToken).get(`/support/jack/conversations/${state.conversationId}`);
|
|
352
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// =========================================================================
|
|
357
|
+
// SUPPORT (Check-ins, Wins)
|
|
358
|
+
// =========================================================================
|
|
359
|
+
console.log(`\n${c.cyan}--- SUPPORT ---${c.reset}\n`);
|
|
360
|
+
|
|
361
|
+
await test('Create daily check-in', async () => {
|
|
362
|
+
const res = await api(state.accessToken).post('/support/check-ins', {
|
|
363
|
+
date: new Date().toISOString().split('T')[0],
|
|
364
|
+
mood: 4, // Valid range 1-5
|
|
365
|
+
energy: 4, // Valid range 1-5
|
|
366
|
+
stayedSober: true,
|
|
367
|
+
notes: 'E2E test check-in',
|
|
368
|
+
});
|
|
369
|
+
// 201 for new, 409 if exists
|
|
370
|
+
if (res.status !== 201 && res.status !== 409) throw new Error(`Status ${res.status}: ${JSON.stringify(res.data)}`);
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
await test('Get check-ins', async () => {
|
|
374
|
+
const res = await api(state.accessToken).get('/support/check-ins');
|
|
375
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
await test('Get today check-in', async () => {
|
|
379
|
+
const res = await api(state.accessToken).get('/support/check-ins/today');
|
|
380
|
+
if (res.status !== 200 && res.status !== 404) throw new Error(`Status ${res.status}`);
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
await test('Get check-in streak', async () => {
|
|
384
|
+
const res = await api(state.accessToken).get('/support/check-ins/streak');
|
|
385
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
await test('Log a win', async () => {
|
|
389
|
+
const res = await api(state.accessToken).post('/support/wins', {
|
|
390
|
+
title: 'Completed E2E tests',
|
|
391
|
+
description: 'Successfully ran all API tests',
|
|
392
|
+
category: 'PERSONAL', // Valid: SOBRIETY, HEALTH, RELATIONSHIP, CAREER, PERSONAL, FINANCIAL, OTHER
|
|
393
|
+
});
|
|
394
|
+
if (res.status !== 201) throw new Error(`Status ${res.status}: ${JSON.stringify(res.data)}`);
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
await test('Get wins', async () => {
|
|
398
|
+
const res = await api(state.accessToken).get('/support/wins');
|
|
399
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
await test('Get wins count', async () => {
|
|
403
|
+
const res = await api(state.accessToken).get('/support/wins/count');
|
|
404
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
// =========================================================================
|
|
408
|
+
// NOTIFICATIONS
|
|
409
|
+
// =========================================================================
|
|
410
|
+
console.log(`\n${c.cyan}--- NOTIFICATIONS ---${c.reset}\n`);
|
|
411
|
+
|
|
412
|
+
await test('Get notifications', async () => {
|
|
413
|
+
const res = await api(state.accessToken).get('/notifications');
|
|
414
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
await test('Get unread count', async () => {
|
|
418
|
+
const res = await api(state.accessToken).get('/notifications/unread-count');
|
|
419
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
// =========================================================================
|
|
423
|
+
// SUBSCRIPTIONS
|
|
424
|
+
// =========================================================================
|
|
425
|
+
console.log(`\n${c.cyan}--- SUBSCRIPTIONS ---${c.reset}\n`);
|
|
426
|
+
|
|
427
|
+
await test('Get subscription plans', async () => {
|
|
428
|
+
const res = await api(state.accessToken).get('/subscriptions/plans');
|
|
429
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
await test('Get my subscription', async () => {
|
|
433
|
+
const res = await api(state.accessToken).get('/subscriptions/me');
|
|
434
|
+
// 200 if subscribed, 404 if not
|
|
435
|
+
if (res.status !== 200 && res.status !== 404) throw new Error(`Status ${res.status}`);
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
// =========================================================================
|
|
439
|
+
// LIBRARY
|
|
440
|
+
// =========================================================================
|
|
441
|
+
console.log(`\n${c.cyan}--- LIBRARY ---${c.reset}\n`);
|
|
442
|
+
|
|
443
|
+
await test('Get library content', async () => {
|
|
444
|
+
const res = await api(state.accessToken).get('/library');
|
|
445
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
await test('Get featured content', async () => {
|
|
449
|
+
const res = await api(state.accessToken).get('/library/featured');
|
|
450
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
// =========================================================================
|
|
454
|
+
// MAP
|
|
455
|
+
// =========================================================================
|
|
456
|
+
console.log(`\n${c.cyan}--- MAP ---${c.reset}\n`);
|
|
457
|
+
|
|
458
|
+
await test('Get map hubs', async () => {
|
|
459
|
+
const res = await api(state.accessToken).get('/map/hubs');
|
|
460
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
await test('Get map events', async () => {
|
|
464
|
+
const res = await api(state.accessToken).get('/map/events');
|
|
465
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
// =========================================================================
|
|
469
|
+
// CLEANUP
|
|
470
|
+
// =========================================================================
|
|
471
|
+
console.log(`\n${c.cyan}--- CLEANUP ---${c.reset}\n`);
|
|
472
|
+
|
|
473
|
+
if (state.bookingId) {
|
|
474
|
+
await test('Cancel booking', async () => {
|
|
475
|
+
const res = await api(state.accessToken).delete(`/bookings/${state.bookingId}`);
|
|
476
|
+
if (res.status !== 204 && res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (state.eventId) {
|
|
481
|
+
await test('Cancel event', async () => {
|
|
482
|
+
const res = await api(state.accessToken).post(`/events/${state.eventId}/cancel`);
|
|
483
|
+
if (res.status !== 200) throw new Error(`Status ${res.status}`);
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// =========================================================================
|
|
488
|
+
// SUMMARY
|
|
489
|
+
// =========================================================================
|
|
490
|
+
console.log(`\n${c.cyan}${'='.repeat(60)}${c.reset}`);
|
|
491
|
+
console.log(`${c.cyan} TEST SUMMARY${c.reset}`);
|
|
492
|
+
console.log(`${c.cyan}${'='.repeat(60)}${c.reset}`);
|
|
493
|
+
console.log(`${c.green}Passed: ${passed}${c.reset}`);
|
|
494
|
+
console.log(`${c.red}Failed: ${failed}${c.reset}`);
|
|
495
|
+
console.log(`Total: ${passed + failed}`);
|
|
496
|
+
console.log(`${c.cyan}${'='.repeat(60)}${c.reset}\n`);
|
|
497
|
+
|
|
498
|
+
process.exit(failed > 0 ? 1 : 0);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Run tests
|
|
502
|
+
runTests().catch(console.error);
|