Fix tests
This commit is contained in:
parent
6d24f3c112
commit
0cc099c00c
3 changed files with 167 additions and 40 deletions
|
|
@ -6,7 +6,8 @@
|
|||
"dev": "tsx watch src/index.ts",
|
||||
"build": "tsc",
|
||||
"start": "node dist/index.js",
|
||||
"test": "tsx --env-file=.env.test tests/api.test.ts",
|
||||
"test": "tsx --env-file=.env.test tests/run-tests.ts",
|
||||
"test:only": "tsx --env-file=.env.test tests/api.test.ts",
|
||||
"test:get-token": "tsx --env-file=.env.test tests/get-token.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
|
|||
|
|
@ -1,22 +1,21 @@
|
|||
const AUTHENTIK_URL = process.env.AUTHENTIK_URL || 'http://localhost:9000';
|
||||
const CLIENT_ID = process.env.CLIENT_ID || 'kaboot-spa';
|
||||
const APP_SLUG = process.env.APP_SLUG || 'kaboot';
|
||||
const USERNAME = process.env.TEST_USERNAME || 'kaboottest';
|
||||
const PASSWORD = process.env.TEST_PASSWORD || 'kaboottest';
|
||||
const CLIENT_SECRET = process.env.CLIENT_SECRET || '';
|
||||
const USERNAME = process.env.TEST_USERNAME || '';
|
||||
const PASSWORD = process.env.TEST_PASSWORD || '';
|
||||
|
||||
async function getTokenWithClientSecret(): Promise<string> {
|
||||
if (!CLIENT_SECRET) throw new Error('CLIENT_SECRET not set');
|
||||
|
||||
async function getTokenViaPasswordGrant(): Promise<string> {
|
||||
const tokenUrl = `${AUTHENTIK_URL}/application/o/token/`;
|
||||
|
||||
const params = new URLSearchParams({
|
||||
grant_type: 'client_credentials',
|
||||
client_id: CLIENT_ID,
|
||||
username: USERNAME,
|
||||
password: PASSWORD,
|
||||
client_secret: CLIENT_SECRET,
|
||||
scope: 'openid profile email',
|
||||
});
|
||||
|
||||
console.log(`Token URL: ${tokenUrl}`);
|
||||
|
||||
console.log(` Trying client_credentials with client_secret...`);
|
||||
const response = await fetch(tokenUrl, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
|
|
@ -25,7 +24,35 @@ async function getTokenViaPasswordGrant(): Promise<string> {
|
|||
|
||||
if (!response.ok) {
|
||||
const error = await response.text();
|
||||
throw new Error(`Password grant failed: ${response.status} - ${error}`);
|
||||
throw new Error(`${response.status} - ${error}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return data.access_token;
|
||||
}
|
||||
|
||||
async function getTokenWithServiceAccount(): Promise<string> {
|
||||
if (!USERNAME || !PASSWORD) throw new Error('USERNAME and PASSWORD not set');
|
||||
|
||||
const tokenUrl = `${AUTHENTIK_URL}/application/o/token/`;
|
||||
const params = new URLSearchParams({
|
||||
grant_type: 'client_credentials',
|
||||
client_id: CLIENT_ID,
|
||||
username: USERNAME,
|
||||
password: PASSWORD,
|
||||
scope: 'openid profile email',
|
||||
});
|
||||
|
||||
console.log(` Trying client_credentials with username/password...`);
|
||||
const response = await fetch(tokenUrl, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: params.toString(),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.text();
|
||||
throw new Error(`${response.status} - ${error}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
|
@ -37,41 +64,57 @@ async function main() {
|
|||
console.log('==========================\n');
|
||||
console.log(`Authentik URL: ${AUTHENTIK_URL}`);
|
||||
console.log(`Client ID: ${CLIENT_ID}`);
|
||||
console.log(`Username: ${USERNAME}`);
|
||||
console.log('');
|
||||
|
||||
try {
|
||||
console.log('Attempting password/client_credentials grant...');
|
||||
const token = await getTokenViaPasswordGrant();
|
||||
console.log('\n✓ Token obtained successfully!\n');
|
||||
console.log('=== ACCESS TOKEN ===');
|
||||
console.log(token);
|
||||
console.log('\n=== EXPORT COMMAND ===');
|
||||
console.log(`export TEST_TOKEN="${token}"`);
|
||||
return;
|
||||
} catch (error) {
|
||||
console.log(`✗ ${error instanceof Error ? error.message : error}\n`);
|
||||
let token: string | null = null;
|
||||
|
||||
if (CLIENT_SECRET) {
|
||||
try {
|
||||
token = await getTokenWithClientSecret();
|
||||
console.log(' ✓ Success!\n');
|
||||
} catch (error) {
|
||||
console.log(` ✗ Failed: ${error instanceof Error ? error.message : error}\n`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('=== MANUAL TOKEN SETUP ===\n');
|
||||
console.log('Option 1: Create a Service Account in Authentik');
|
||||
console.log(' 1. Go to: Admin > Directory > Users');
|
||||
console.log(' 2. Click "Create Service Account"');
|
||||
console.log(' 3. Give it a name (e.g., "kaboot-test")');
|
||||
console.log(' 4. Copy the username and token generated');
|
||||
console.log(' 5. Run: TEST_USERNAME=<username> TEST_PASSWORD=<token> npm run test:get-token\n');
|
||||
if (!token && USERNAME && PASSWORD) {
|
||||
try {
|
||||
token = await getTokenWithServiceAccount();
|
||||
console.log(' ✓ Success!\n');
|
||||
} catch (error) {
|
||||
console.log(` ✗ Failed: ${error instanceof Error ? error.message : error}\n`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Option 2: Get token from browser');
|
||||
console.log(' 1. Log into Kaboot frontend with Authentik');
|
||||
console.log(' 2. Open browser DevTools > Application > Local Storage');
|
||||
console.log(' 3. Find the oidc.user entry');
|
||||
console.log(' 4. Copy the access_token value');
|
||||
console.log(' 5. Run: export TEST_TOKEN="<token>"\n');
|
||||
if (token) {
|
||||
console.log('=== ACCESS TOKEN ===');
|
||||
console.log(token);
|
||||
console.log('\n=== FOR .env.test ===');
|
||||
console.log(`TEST_TOKEN=${token}`);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Option 3: Use Authentik API directly');
|
||||
console.log(' 1. Go to: Admin > Directory > Tokens & App passwords');
|
||||
console.log(' 2. Create a new token for your user');
|
||||
console.log(' 3. Use that token for API testing\n');
|
||||
console.log('=== SETUP INSTRUCTIONS ===\n');
|
||||
console.log('Method 1: Client Secret (Recommended for testing)\n');
|
||||
console.log(' 1. Go to Authentik Admin: http://localhost:9000/if/admin/');
|
||||
console.log(' 2. Navigate to: Applications → Providers → Kaboot OAuth2');
|
||||
console.log(' 3. Change "Client type" from "Public" to "Confidential"');
|
||||
console.log(' 4. Copy the "Client Secret" value');
|
||||
console.log(' 5. Add to server/.env.test:');
|
||||
console.log(' CLIENT_SECRET=<paste-secret-here>\n');
|
||||
|
||||
console.log('Method 2: Service Account + App Password\n');
|
||||
console.log(' 1. Go to Authentik Admin: http://localhost:9000/if/admin/');
|
||||
console.log(' 2. Navigate to: Directory → Users');
|
||||
console.log(' 3. Click "Create Service Account"');
|
||||
console.log(' 4. Name it (e.g., "kaboot-test")');
|
||||
console.log(' 5. After creation, click on the user → "App passwords" tab');
|
||||
console.log(' 6. Create a new app password, copy the token');
|
||||
console.log(' 7. Bind the service account to Kaboot app:');
|
||||
console.log(' Applications → Kaboot → Policy/Group/User Bindings → Bind existing user');
|
||||
console.log(' 8. Add to server/.env.test:');
|
||||
console.log(' TEST_USERNAME=<service-account-username>');
|
||||
console.log(' TEST_PASSWORD=<app-password-token>\n');
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
|
|
|
|||
83
server/tests/run-tests.ts
Normal file
83
server/tests/run-tests.ts
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
import { spawn } from 'child_process';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname, join } from 'path';
|
||||
|
||||
const AUTHENTIK_URL = process.env.AUTHENTIK_URL || 'http://localhost:9000';
|
||||
const CLIENT_ID = process.env.CLIENT_ID || 'kaboot-spa';
|
||||
const USERNAME = process.env.TEST_USERNAME || '';
|
||||
const PASSWORD = process.env.TEST_PASSWORD || '';
|
||||
|
||||
async function getToken(): Promise<string> {
|
||||
if (!USERNAME || !PASSWORD) {
|
||||
throw new Error(
|
||||
'TEST_USERNAME and TEST_PASSWORD must be set in .env.test\n' +
|
||||
'See tests/README.md for setup instructions.'
|
||||
);
|
||||
}
|
||||
|
||||
const tokenUrl = `${AUTHENTIK_URL}/application/o/token/`;
|
||||
const params = new URLSearchParams({
|
||||
grant_type: 'client_credentials',
|
||||
client_id: CLIENT_ID,
|
||||
username: USERNAME,
|
||||
password: PASSWORD,
|
||||
scope: 'openid profile email',
|
||||
});
|
||||
|
||||
const response = await fetch(tokenUrl, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: params.toString(),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.text();
|
||||
throw new Error(`Failed to get token: ${response.status} - ${error}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return data.access_token;
|
||||
}
|
||||
|
||||
async function runTests(token: string): Promise<number> {
|
||||
return new Promise((resolve) => {
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const testFile = join(__dirname, 'api.test.ts');
|
||||
|
||||
const child = spawn(process.execPath, [
|
||||
'--import', 'tsx',
|
||||
testFile
|
||||
], {
|
||||
env: {
|
||||
...process.env,
|
||||
TEST_TOKEN: token,
|
||||
},
|
||||
stdio: 'inherit',
|
||||
});
|
||||
|
||||
child.on('close', (code) => {
|
||||
resolve(code ?? 1);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('Kaboot API Test Runner');
|
||||
console.log('======================\n');
|
||||
|
||||
console.log('Obtaining access token from Authentik...');
|
||||
let token: string;
|
||||
try {
|
||||
token = await getToken();
|
||||
console.log(' Token obtained successfully.\n');
|
||||
} catch (error) {
|
||||
console.error(` Failed: ${error instanceof Error ? error.message : error}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('Running API tests...\n');
|
||||
const exitCode = await runTests(token);
|
||||
process.exit(exitCode);
|
||||
}
|
||||
|
||||
main();
|
||||
Loading…
Add table
Add a link
Reference in a new issue