From 77a1a2c7b11715e1858da1a1bdd438fc24d84f7a Mon Sep 17 00:00:00 2001 From: Rob Rudin Date: Thu, 20 Nov 2025 13:07:19 -0500 Subject: [PATCH] MLE-24194 Fixing checkConnection and better tests This was way harder than it should have been, but Copilot finally got it done. checkConnection had the wrong return type, so the method didn't actually working in a "real" TS test - and we now have a "real" TS test. See the Copilot-authored README for explanation. --- .gitignore | 5 +- Jenkinsfile | 15 +++ lib/responder.js | 2 +- marklogic.d.ts | 19 +++- package-lock.json | 8 ++ package.json | 5 +- test-typescript/README.md | 86 +++++++++++++-- .../checkConnection-runtime.test.ts | 97 +++++++++++++++++ test-typescript/connection-methods.test.ts | 71 +++---------- test-typescript/error-examples.test.ts | 31 ++---- test-typescript/type-constraints.test.ts | 39 ++----- tsconfig.json | 5 +- typescript-test-project/package.json | 4 +- typescript-test-project/test.ts | 100 +++--------------- typescript-test-project/tsconfig.json | 3 +- 15 files changed, 275 insertions(+), 215 deletions(-) create mode 100644 test-typescript/checkConnection-runtime.test.ts diff --git a/.gitignore b/.gitignore index 5598f296..441e8861 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,7 @@ test-app/containerLogs test-complete-app/build test-complete-app/.gradle test-complete-app-mlDeploy/build -test-complete-app-mlDeploy/.gradle \ No newline at end of file +test-complete-app-mlDeploy/.gradle + +# Compiled TypeScript test files +test-typescript/*.js diff --git a/Jenkinsfile b/Jenkinsfile index 14216749..12f8be71 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -78,6 +78,17 @@ def runTypeCheck() { ''' } +def runTypeScriptTests() { + sh label: 'run-typescript-tests', script: ''' + export PATH=${NODE_HOME_DIR}/bin:$PATH + cd node-client-api + npm ci + npm run test:compile + ./node_modules/.bin/mocha --timeout 10000 test-typescript/*.js --reporter mocha-junit-reporter --reporter-options mochaFile=$WORKSPACE/test-typescript-reports.xml || true + ''' + junit '**/*test-typescript-reports.xml' +} + def runE2ETests() { sh label: 'run-e2e-tests', script: ''' export PATH=${NODE_HOME_DIR}/bin:$PATH @@ -142,6 +153,7 @@ pipeline { runTypeCheck() runDockerCompose('ml-docker-db-dev-tierpoint.bed-artifactory.bedford.progress.com/marklogic/marklogic-server-ubi:latest-12') runTests() + runTypeScriptTests() runE2ETests() } post { @@ -165,6 +177,7 @@ pipeline { steps { runDockerCompose('ml-docker-db-dev-tierpoint.bed-artifactory.bedford.progress.com/marklogic/marklogic-server-ubi:latest-11') runTests() + runTypeScriptTests() runE2ETests() } post { @@ -185,6 +198,7 @@ pipeline { steps { runDockerCompose('ml-docker-db-dev-tierpoint.bed-artifactory.bedford.progress.com/marklogic/marklogic-server-ubi:latest-12') runTests() + runTypeScriptTests() runE2ETests() } post { @@ -205,6 +219,7 @@ pipeline { steps { runDockerCompose('ml-docker-db-dev-tierpoint.bed-artifactory.bedford.progress.com/marklogic/marklogic-server-ubi:latest-10') runTests() + runTypeScriptTests() runE2ETests() } post { diff --git a/lib/responder.js b/lib/responder.js index 412ca64d..b1f48f05 100644 --- a/lib/responder.js +++ b/lib/responder.js @@ -1224,7 +1224,7 @@ function operationResultStream() { function operationErrorListener(error) { /*jshint validthis:true */ const operation = this; - if(operation.client.connectionParams.apiKey){ + if(operation.client.connectionParams && operation.client.connectionParams.apiKey){ if(error.statusCode === 401 && operation.expiration <= (new Date())){ if(!operation.lockAccessToken){ operation.lockAccessToken = true; diff --git a/marklogic.d.ts b/marklogic.d.ts index c91aa0b0..6c75f1a7 100644 --- a/marklogic.d.ts +++ b/marklogic.d.ts @@ -79,10 +79,11 @@ declare module 'marklogic' { export interface DatabaseClient { /** * Tests if a connection is successful. + * Call .result() to get a promise. * @since 2.1 - * @returns A promise that resolves to an object indicating connection status + * @returns A result provider with a result() method */ - checkConnection(): Promise; + checkConnection(): ResultProvider; /** * Releases the client and destroys the agent. @@ -92,6 +93,20 @@ declare module 'marklogic' { release(): void; } + /** + * A result provider that wraps asynchronous operations. + * Call .result() to get a Promise for the result. + */ + export interface ResultProvider { + /** + * Gets a promise for the operation result. + * @param onFulfilled - Optional callback for success + * @param onRejected - Optional callback for errors + * @returns A promise that resolves to the result + */ + result(onFulfilled?: (value: T) => void, onRejected?: (reason: any) => void): Promise; + } + /** * Creates a DatabaseClient object for accessing a database. * @param config - Configuration for connecting to the database diff --git a/package-lock.json b/package-lock.json index eccae9c0..b72cfb09 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ }, "devDependencies": { "@jsdoc/salty": "0.2.9", + "@types/mocha": "10.0.10", "@types/node": "22.10.1", "ajv": "8.17.1", "ast-types": "0.14.2", @@ -460,6 +461,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/mocha": { + "version": "10.0.10", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", + "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { "version": "22.10.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz", diff --git a/package.json b/package.json index 2ff3638f..f76806c4 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,9 @@ "scripts": { "doc": "jsdoc -c jsdoc.json lib/*.js README.md", "lint": "gulp lint", - "test:types": "tsc --noEmit" + "test:types": "tsc --noEmit", + "test:compile": "tsc test-typescript/checkConnection-runtime.test.ts", + "pretest:typescript": "npm run test:compile" }, "keywords": [ "marklogic", @@ -53,6 +55,7 @@ }, "devDependencies": { "@jsdoc/salty": "0.2.9", + "@types/mocha": "10.0.10", "@types/node": "22.10.1", "ajv": "8.17.1", "ast-types": "0.14.2", diff --git a/test-typescript/README.md b/test-typescript/README.md index 2f9bcf4f..79a07786 100644 --- a/test-typescript/README.md +++ b/test-typescript/README.md @@ -2,23 +2,72 @@ This directory contains TypeScript tests to verify that the type definitions in `marklogic.d.ts` work correctly. -## How to Test Types +## Types of Tests + +### 1. Compile-Only Tests (Type Checking) +Files like `basic-types.test.ts`, `connection-methods.test.ts`, `type-constraints.test.ts`, `error-examples.test.ts` + +- **Purpose**: Verify that TypeScript code compiles without errors +- **Execution**: Not executed at runtime - only compiled +- **Speed**: Very fast (seconds) +- **Requirements**: No MarkLogic server needed +- **Run with**: `npm run test:types` + +These tests validate: +- Type definitions are syntactically correct +- Type constraints work (e.g., `authType` only accepts valid values) +- IntelliSense will work for users +- Type errors are caught at compile time + +### 2. Runtime Tests +Files like `checkConnection-runtime.test.ts` -Run the type checking with: +- **Purpose**: Verify that TypeScript definitions match actual runtime behavior +- **Execution**: Compiled to JavaScript and executed with mocha +- **Speed**: Slower (requires MarkLogic) +- **Requirements**: MarkLogic server running +- **Run with**: `npm run test:compile && npx mocha test-typescript/*.js` +These tests validate: +- Types compile correctly (compile-time check) +- Real API calls return the expected types (runtime check) +- TypeScript definitions accurately reflect the actual JavaScript behavior + +## How to Test Types + +### Type Checking Only ```bash npm run test:types ``` -This command runs `tsc --noEmit`, which checks for TypeScript errors without generating JavaScript files. +This runs `tsc --noEmit`, which checks for TypeScript errors without generating JavaScript files. + +### Runtime Tests +```bash +npm run test:compile # Compile TypeScript tests to JavaScript +npx mocha test-typescript/*.js # Run compiled tests against MarkLogic +``` + +Or in one command: +```bash +npm run test:compile && npx mocha test-typescript/*.js +``` + +## Why Two Approaches? -## Why This Approach? +**Compile-only tests** are great for: +- Fast feedback during development +- Catching type definition errors quickly +- CI/CD pre-flight checks (before spinning up MarkLogic) +- Validating that autocomplete/IntelliSense will work -TypeScript's compiler is the best way to test type definitions because: -- It catches type errors at compile time (before runtime) -- It validates type constraints (like union types for `authType`) -- It ensures IntelliSense and autocomplete will work for users -- It's fast and doesn't require running actual code +**Runtime tests** are essential for: +- Ensuring type definitions match actual behavior +- Catching mismatches between declared types and runtime values +- Integration testing with real MarkLogic instances +- Preventing issues like returning `{}` when a `Promise` was expected + +Both approaches complement each other for comprehensive type safety validation. ## Example: Testing for Type Errors @@ -40,3 +89,22 @@ error TS2322: Type '"invalid-type"' is not assignable to type 'basic' | 'digest' ``` This confirms your types are working correctly! + +## Adding New Tests + +### To add a compile-only test: +1. Create a `.test.ts` file in this directory +2. Use `/// ` to load types +3. Import types with: `type MyType = import('marklogic').MyType;` +4. Write code that should compile (or intentionally fail) +5. Run `npm run test:types` to verify + +### To add a runtime test: +1. Create a `.test.ts` file in this directory +2. Use the same reference and import pattern as above +3. Import test framework: `import should = require('should');` +4. Use `describe`/`it` blocks like normal mocha tests +5. Make actual API calls to MarkLogic +6. Compile with `npm run test:compile` and run with mocha + +**Note**: Compiled `.js` files are gitignored and regenerated on each test run. diff --git a/test-typescript/checkConnection-runtime.test.ts b/test-typescript/checkConnection-runtime.test.ts new file mode 100644 index 00000000..5c79aa28 --- /dev/null +++ b/test-typescript/checkConnection-runtime.test.ts @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2015-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. + */ + +/// + +/** + * TypeScript runtime test to validate that checkConnection returns ResultProvider. + * This test ensures the TypeScript definitions match the actual runtime behavior + * by making real calls to MarkLogic AND verifying types at compile time. + */ + +import should = require('should'); +const marklogic = require('..'); +const testconfig = require('../etc/test-config-qa.js'); + +const db = marklogic.createDatabaseClient(testconfig.restReaderConnection); + +// Type alias for easier reference +type ResultProvider = import('marklogic').ResultProvider; +type ConnectionCheckResult = import('marklogic').ConnectionCheckResult; +type DatabaseClientConfig = import('marklogic').DatabaseClientConfig; + +describe('checkConnection ResultProvider validation', function() { + + it('should return ResultProvider with .result() method', function(done) { + // This validates that checkConnection returns a ResultProvider + // TypeScript will verify the type at compile time + const resultProvider: ResultProvider = db.checkConnection(); + + // Verify it has a .result() method (core requirement for ResultProvider) + should(resultProvider).have.property('result'); + should(resultProvider.result).be.a.Function(); + + // Call .result() to get a Promise + const promise: Promise = resultProvider.result(); + + // Verify .result() returns a Promise (thenable) + should(promise).have.property('then'); + should(promise.then).be.a.Function(); + + // Verify the Promise resolves to ConnectionCheckResult + promise.then((response: ConnectionCheckResult) => { + should(response).have.property('connected'); + should(response.connected).be.a.Boolean(); + + if (response.connected === true) { + done(); + } else { + done(new Error('Expected connection to succeed but got: ' + JSON.stringify(response))); + } + }).catch(done); + }); + + it('should work with async/await pattern', async function() { + // TypeScript verifies the return type matches ConnectionCheckResult + const result: ConnectionCheckResult = await db.checkConnection().result(); + + // Verify result shape matches ConnectionCheckResult + should(result).have.property('connected'); + should(result.connected).be.a.Boolean(); + should(result.connected).equal(true); + }); + + it('should have error properties when connection fails', function(done) { + // Test with wrong password to get a failed connection + const config: DatabaseClientConfig = { + host: testconfig.restReaderConnection.host, + user: testconfig.restReaderConnection.user, + password: 'wrongpassword', // Invalid password + port: testconfig.restReaderConnection.port, + authType: testconfig.restReaderConnection.authType + }; + const db1 = marklogic.createDatabaseClient(config); + + db1.checkConnection().result().then((response: ConnectionCheckResult) => { + should(response).have.property('connected'); + should(response.connected).be.a.Boolean(); + + if (response.connected === false) { + // When connected is false, optional error properties should exist + should(response).have.property('httpStatusCode'); + should(response.httpStatusCode).be.a.Number(); + should(response).have.property('httpStatusMessage'); + should(response.httpStatusMessage).be.a.String(); + } + + db1.release(); + done(); + }).catch(done); + }); + + after(function(done) { + db.release(); + done(); + }); +}); diff --git a/test-typescript/connection-methods.test.ts b/test-typescript/connection-methods.test.ts index c3571ba4..65bb61bc 100644 --- a/test-typescript/connection-methods.test.ts +++ b/test-typescript/connection-methods.test.ts @@ -2,6 +2,8 @@ * Copyright (c) 2015-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. */ +/// + /** * TypeScript type checking tests for connection-related methods. * @@ -14,42 +16,14 @@ * Run with: npm run test:types */ -// Create test types that should match the actual marklogic types -type ConnectionCheckResult = { - connected: boolean; - httpStatusCode?: number; - httpStatusMessage?: string; -}; - -type DatabaseClient = { - checkConnection(): Promise; - release(): void; -}; - -type DatabaseClientConfig = { - host?: string; - port?: number; - user?: string; - password?: string; -}; - -// Simulate the marklogic module interface -type MarkLogicModule = { - createDatabaseClient(config: DatabaseClientConfig): DatabaseClient; - releaseClient(client: DatabaseClient): void; -}; +import type { DatabaseClient, ConnectionCheckResult } from 'marklogic'; +import * as marklogic from 'marklogic'; // Test checkConnection() return type -async function testCheckConnection(marklogic: MarkLogicModule) { - const client = marklogic.createDatabaseClient({ - host: 'localhost', - port: 8000, - user: 'admin', - password: 'admin' - }); - - // Should return a Promise - const result = await client.checkConnection(); +async function testCheckConnection(client: DatabaseClient) { + // Should return a ResultProvider + const resultProvider = client.checkConnection(); + const result = await resultProvider.result(); // result.connected should be boolean const isConnected: boolean = result.connected; @@ -66,14 +40,7 @@ async function testCheckConnection(marklogic: MarkLogicModule) { } // Test release() method on client -function testRelease(marklogic: MarkLogicModule) { - const client = marklogic.createDatabaseClient({ - host: 'localhost', - port: 8000, - user: 'admin', - password: 'admin' - }); - +function testRelease(client: DatabaseClient) { // Should be callable with no return value client.release(); @@ -81,14 +48,7 @@ function testRelease(marklogic: MarkLogicModule) { } // Test releaseClient() standalone function -function testReleaseClientFunction(marklogic: MarkLogicModule) { - const client = marklogic.createDatabaseClient({ - host: 'localhost', - port: 8000, - user: 'admin', - password: 'admin' - }); - +function testReleaseClientFunction(client: DatabaseClient) { // Should accept a DatabaseClient and return void marklogic.releaseClient(client); @@ -96,16 +56,9 @@ function testReleaseClientFunction(marklogic: MarkLogicModule) { } // Test proper cleanup pattern -async function testProperCleanupPattern(marklogic: MarkLogicModule) { - const client = marklogic.createDatabaseClient({ - host: 'localhost', - port: 8000, - user: 'admin', - password: 'admin' - }); - +async function testProperCleanupPattern(client: DatabaseClient) { try { - const result = await client.checkConnection(); + const result = await client.checkConnection().result(); if (result.connected) { console.log('Connected successfully!'); // Do database operations... diff --git a/test-typescript/error-examples.test.ts b/test-typescript/error-examples.test.ts index ee059cb3..ebfd0b7c 100644 --- a/test-typescript/error-examples.test.ts +++ b/test-typescript/error-examples.test.ts @@ -2,50 +2,35 @@ * Copyright (c) 2015-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. */ +/// + // This file demonstrates TypeScript catching type errors // To see the errors, uncomment sections below and run: npm run test:types -type ConfigType = { - host?: string; - port?: number; - user?: string; - password?: string; - database?: string; - authType?: 'basic' | 'digest' | 'application-level' | 'certificate' | 'kerberos' | 'saml' | 'cloud'; - ssl?: boolean; - ca?: string | string[] | Buffer | Buffer[]; - cert?: string | Buffer; - key?: string | Buffer; - pfx?: Buffer; - passphrase?: string; - rejectUnauthorized?: boolean; - token?: string; - agent?: any; - apiVersion?: string; -}; +import type { DatabaseClientConfig } from 'marklogic'; // ✅ This works - valid authType -const validConfig: ConfigType = { +const validConfig: DatabaseClientConfig = { authType: 'digest' }; // ❌ UNCOMMENT THIS to see TypeScript catch an invalid authType: -// const invalidAuthType: ConfigType = { +// const invalidAuthType: DatabaseClientConfig = { // authType: 'invalid-type' // Error: Type '"invalid-type"' is not assignable to type 'basic' | 'digest' | ... // }; // ❌ UNCOMMENT THIS to see TypeScript catch wrong type for port: -// const invalidPort: ConfigType = { +// const invalidPort: DatabaseClientConfig = { // port: 'not-a-number' // Error: Type 'string' is not assignable to type 'number' // }; // ❌ UNCOMMENT THIS to see TypeScript catch wrong type for ssl: -// const invalidSsl: ConfigType = { +// const invalidSsl: DatabaseClientConfig = { // ssl: 'yes' // Error: Type 'string' is not assignable to type 'boolean' // }; // ❌ UNCOMMENT THIS to see TypeScript catch invalid certificate type: -// const invalidCert: ConfigType = { +// const invalidCert: DatabaseClientConfig = { // cert: 123 // Error: Type 'number' is not assignable to type 'string | Buffer' // }; diff --git a/test-typescript/type-constraints.test.ts b/test-typescript/type-constraints.test.ts index 424fcddc..fe4fb9ea 100644 --- a/test-typescript/type-constraints.test.ts +++ b/test-typescript/type-constraints.test.ts @@ -2,37 +2,16 @@ * Copyright (c) 2015-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. */ +/// + // Simple TypeScript type checking test // This test validates the DatabaseClientConfig interface without needing the actual module // Run with: npm run test:types -/** - * To test the types, we'll reference them directly from the .d.ts file - * This simulates what would happen when a user imports the module - */ - -// Test by creating a type that should match DatabaseClientConfig -type TestConfig = { - host?: string; - port?: number; - user?: string; - password?: string; - database?: string; - authType?: 'basic' | 'digest' | 'application-level' | 'certificate' | 'kerberos' | 'saml' | 'cloud'; - ssl?: boolean; - ca?: string | string[] | Buffer | Buffer[]; - cert?: string | Buffer; - key?: string | Buffer; - pfx?: Buffer; - passphrase?: string; - rejectUnauthorized?: boolean; - token?: string; - agent?: any; - apiVersion?: string; -}; +import type { DatabaseClientConfig } from 'marklogic'; // Valid configurations that should work -const validConfig1: TestConfig = { +const validConfig1: DatabaseClientConfig = { host: 'localhost', port: 8000, user: 'admin', @@ -40,7 +19,7 @@ const validConfig1: TestConfig = { authType: 'digest' }; -const validConfig2: TestConfig = { +const validConfig2: DatabaseClientConfig = { host: 'secure.marklogic.com', port: 8443, user: 'admin', @@ -53,12 +32,12 @@ const validConfig2: TestConfig = { // Testing type constraints - these should cause errors if uncommented: // Error: Invalid authType -// const invalidAuth: TestConfig = { +// const invalidAuth: DatabaseClientConfig = { // authType: 'invalid-type' as any // }; // Testing that authType is properly restricted -const validAuthTypes: Array = [ +const validAuthTypes: Array = [ 'basic', 'digest', 'application-level', @@ -70,13 +49,13 @@ const validAuthTypes: Array = [ ]; // Testing Buffer and string union types for certificates -const certTest1: TestConfig = { +const certTest1: DatabaseClientConfig = { ca: 'string cert', cert: Buffer.from('cert'), key: 'string key' }; -const certTest2: TestConfig = { +const certTest2: DatabaseClientConfig = { ca: ['cert1', 'cert2'], cert: 'string cert', key: Buffer.from('key') diff --git a/tsconfig.json b/tsconfig.json index ff1e0892..12b781b5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,11 +5,12 @@ "lib": ["ES2020"], "strict": true, "esModuleInterop": true, - "skipLibCheck": false, + "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "moduleResolution": "node", "resolveJsonModule": true, - "noEmit": true + "noEmit": false, + "outDir": "test-typescript" }, "include": ["test-typescript/**/*"], "exclude": ["node_modules", "test-typescript/basic-types.test.ts"] diff --git a/typescript-test-project/package.json b/typescript-test-project/package.json index 7f38c134..38ba9c39 100644 --- a/typescript-test-project/package.json +++ b/typescript-test-project/package.json @@ -6,7 +6,9 @@ "scripts": { "setup": "npm install .. && npm install", "typecheck": "tsc --noEmit", - "test": "npm run typecheck" + "build": "tsc", + "start": "node test.js", + "test": "npm run build && npm run start" }, "keywords": [ "marklogic", diff --git a/typescript-test-project/test.ts b/typescript-test-project/test.ts index 2c58e4ba..dc45f1fe 100644 --- a/typescript-test-project/test.ts +++ b/typescript-test-project/test.ts @@ -2,97 +2,27 @@ * Copyright (c) 2015-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. */ -/** - * Realistic TypeScript usage example for MarkLogic Node.js Client - * - * This file demonstrates how users will consume the library with TypeScript. - * - * Setup: - * npm run setup # First time only - * npm test # Check types - * - * Try this: - * - Start typing to see autocomplete - * - Hover over methods to see documentation - * - Uncomment error examples to see TypeScript catch mistakes - */ - import * as marklogic from 'marklogic'; -// Example: Create a client with autocomplete support -const client = marklogic.createDatabaseClient({ - host: 'localhost', - port: 8000, - user: 'admin', - password: 'admin', - authType: 'digest' // Try typing here - autocomplete suggests all valid auth types! -}); - -// Example: Test connection with proper typing -async function testConnection() { - const result = await client.checkConnection(); - - // TypeScript knows the shape of ConnectionCheckResult - if (result.connected) { - console.log('✅ Connected successfully!'); - } else { - // These optional properties only exist when connected = false - console.error(`❌ Connection failed: ${result.httpStatusCode} - ${result.httpStatusMessage}`); - } - - return result; -} - -// Example: Proper cleanup pattern -async function properUsagePattern() { - const db = marklogic.createDatabaseClient({ - host: 'localhost', - port: 8000, - user: 'admin', - password: 'admin' - }); +const testConfig = require('../etc/test-config.js'); +const client = marklogic.createDatabaseClient(testConfig.restWriterConnection); +async function run() { try { - const status = await db.checkConnection(); - if (status.connected) { - console.log('Ready to work with database'); - // Do your database operations here... + const result = await client.checkConnection().result(); + + if (result.connected) { + console.log('✅ Connected successfully!'); + } else { + console.error(`❌ Connection failed: ${result.httpStatusCode} - ${result.httpStatusMessage}`); + process.exit(1); } } finally { - // Always clean up - TypeScript knows this method exists - db.release(); - - // Alternative: use the standalone function - // marklogic.releaseClient(db); + client.release(); } } -// ============================================================================= -// ERROR EXAMPLES - Uncomment these to see TypeScript catch mistakes! -// ============================================================================= - -// ❌ Error: Invalid authType value -// const badAuthType = marklogic.createDatabaseClient({ -// authType: 'invalid-type' -// }); - -// ❌ Error: port should be number, not string -// const badPort = marklogic.createDatabaseClient({ -// port: '8000' -// }); - -// ❌ Error: ConnectionCheckResult.connected must be boolean -// const badResult: marklogic.ConnectionCheckResult = { -// connected: 'yes' // Error: string is not assignable to boolean -// }; - -// ❌ Error: httpStatusCode must be number -// const badStatusCode: marklogic.ConnectionCheckResult = { -// connected: false, -// httpStatusCode: 'error' // Error: string is not assignable to number -// }; - -console.log('✅ TypeScript validation complete!'); - -// Export functions to prevent unused warnings -export { testConnection, properUsagePattern }; +run().catch((error) => { + console.error('❌ Test failed:', error); + process.exit(1); +}); diff --git a/typescript-test-project/tsconfig.json b/typescript-test-project/tsconfig.json index bdc0577a..efc3c3cb 100644 --- a/typescript-test-project/tsconfig.json +++ b/typescript-test-project/tsconfig.json @@ -24,7 +24,8 @@ "noFallthroughCasesInSwitch": true, /* Emit */ - "noEmit": true, + "noEmit": false, + "outDir": "./", "esModuleInterop": true, "forceConsistentCasingInFileNames": true,