From 8477eeaa817731e3264ea5607d1187e49d2e9d32 Mon Sep 17 00:00:00 2001 From: Surya Prashanth Date: Tue, 28 Oct 2025 19:22:41 +0530 Subject: [PATCH 1/6] move existing tests under unit folder --- tests/{ => unit}/README.md | 0 tests/{ => unit}/constants.ts | 0 tests/{ => unit}/customers/customers.test.ts | 0 .../customers/properties-options.test.ts | 0 tests/{ => unit}/customers/requests.test.ts | 0 tests/{ => unit}/customers/work-items.test.ts | 0 tests/{ => unit}/cycle.test.ts | 0 tests/{ => unit}/epic.test.ts | 0 tests/{ => unit}/intake.test.ts | 0 tests/{ => unit}/label.test.ts | 0 tests/{ => unit}/module.test.ts | 0 tests/{ => unit}/oauth.test.ts | 0 tests/{ => unit}/page.test.ts | 0 tests/{ => unit}/project.test.ts | 0 tests/{ => unit}/run-all.test.ts | 0 tests/unit/setup.ts | 43 +++++++++++++++++++ tests/{ => unit}/state.test.ts | 0 tests/{ => unit}/test-utils.ts | 0 .../properties-options.test.ts | 0 .../work-item-types/properties-values.test.ts | 0 .../{ => unit}/work-item-types/types.test.ts | 0 .../{ => unit}/work-items/activities.test.ts | 0 tests/{ => unit}/work-items/comments.test.ts | 0 tests/{ => unit}/work-items/links.test.ts | 0 tests/{ => unit}/work-items/relations.test.ts | 0 .../{ => unit}/work-items/work-items.test.ts | 0 tests/{ => unit}/work-items/work-logs.test.ts | 0 27 files changed, 43 insertions(+) rename tests/{ => unit}/README.md (100%) rename tests/{ => unit}/constants.ts (100%) rename tests/{ => unit}/customers/customers.test.ts (100%) rename tests/{ => unit}/customers/properties-options.test.ts (100%) rename tests/{ => unit}/customers/requests.test.ts (100%) rename tests/{ => unit}/customers/work-items.test.ts (100%) rename tests/{ => unit}/cycle.test.ts (100%) rename tests/{ => unit}/epic.test.ts (100%) rename tests/{ => unit}/intake.test.ts (100%) rename tests/{ => unit}/label.test.ts (100%) rename tests/{ => unit}/module.test.ts (100%) rename tests/{ => unit}/oauth.test.ts (100%) rename tests/{ => unit}/page.test.ts (100%) rename tests/{ => unit}/project.test.ts (100%) rename tests/{ => unit}/run-all.test.ts (100%) create mode 100644 tests/unit/setup.ts rename tests/{ => unit}/state.test.ts (100%) rename tests/{ => unit}/test-utils.ts (100%) rename tests/{ => unit}/work-item-types/properties-options.test.ts (100%) rename tests/{ => unit}/work-item-types/properties-values.test.ts (100%) rename tests/{ => unit}/work-item-types/types.test.ts (100%) rename tests/{ => unit}/work-items/activities.test.ts (100%) rename tests/{ => unit}/work-items/comments.test.ts (100%) rename tests/{ => unit}/work-items/links.test.ts (100%) rename tests/{ => unit}/work-items/relations.test.ts (100%) rename tests/{ => unit}/work-items/work-items.test.ts (100%) rename tests/{ => unit}/work-items/work-logs.test.ts (100%) diff --git a/tests/README.md b/tests/unit/README.md similarity index 100% rename from tests/README.md rename to tests/unit/README.md diff --git a/tests/constants.ts b/tests/unit/constants.ts similarity index 100% rename from tests/constants.ts rename to tests/unit/constants.ts diff --git a/tests/customers/customers.test.ts b/tests/unit/customers/customers.test.ts similarity index 100% rename from tests/customers/customers.test.ts rename to tests/unit/customers/customers.test.ts diff --git a/tests/customers/properties-options.test.ts b/tests/unit/customers/properties-options.test.ts similarity index 100% rename from tests/customers/properties-options.test.ts rename to tests/unit/customers/properties-options.test.ts diff --git a/tests/customers/requests.test.ts b/tests/unit/customers/requests.test.ts similarity index 100% rename from tests/customers/requests.test.ts rename to tests/unit/customers/requests.test.ts diff --git a/tests/customers/work-items.test.ts b/tests/unit/customers/work-items.test.ts similarity index 100% rename from tests/customers/work-items.test.ts rename to tests/unit/customers/work-items.test.ts diff --git a/tests/cycle.test.ts b/tests/unit/cycle.test.ts similarity index 100% rename from tests/cycle.test.ts rename to tests/unit/cycle.test.ts diff --git a/tests/epic.test.ts b/tests/unit/epic.test.ts similarity index 100% rename from tests/epic.test.ts rename to tests/unit/epic.test.ts diff --git a/tests/intake.test.ts b/tests/unit/intake.test.ts similarity index 100% rename from tests/intake.test.ts rename to tests/unit/intake.test.ts diff --git a/tests/label.test.ts b/tests/unit/label.test.ts similarity index 100% rename from tests/label.test.ts rename to tests/unit/label.test.ts diff --git a/tests/module.test.ts b/tests/unit/module.test.ts similarity index 100% rename from tests/module.test.ts rename to tests/unit/module.test.ts diff --git a/tests/oauth.test.ts b/tests/unit/oauth.test.ts similarity index 100% rename from tests/oauth.test.ts rename to tests/unit/oauth.test.ts diff --git a/tests/page.test.ts b/tests/unit/page.test.ts similarity index 100% rename from tests/page.test.ts rename to tests/unit/page.test.ts diff --git a/tests/project.test.ts b/tests/unit/project.test.ts similarity index 100% rename from tests/project.test.ts rename to tests/unit/project.test.ts diff --git a/tests/run-all.test.ts b/tests/unit/run-all.test.ts similarity index 100% rename from tests/run-all.test.ts rename to tests/unit/run-all.test.ts diff --git a/tests/unit/setup.ts b/tests/unit/setup.ts new file mode 100644 index 0000000..cb94b9f --- /dev/null +++ b/tests/unit/setup.ts @@ -0,0 +1,43 @@ +// Jest setup file for global test configuration +import { config } from './unit/constants'; + +// Set up global test configuration +beforeAll(() => { + // Verify required environment variables are set + const requiredEnvVars = [ + 'PLANE_API_KEY', + 'PLANE_BASE_URL', + 'TEST_WORKSPACE_SLUG', + 'TEST_PROJECT_ID', + 'TEST_USER_ID', + 'TEST_WORK_ITEM_ID', + 'TEST_WORK_ITEM_ID_2', + 'TEST_CUSTOMER_ID', + 'TEST_WORK_ITEM_TYPE_ID', + 'TEST_CUSTOM_TEXT_PROPERTY_ID' + ]; + + const missingVars = requiredEnvVars.filter(varName => !process.env[varName]); + + if (missingVars.length > 0) { + throw new Error(`Missing required environment variables: ${missingVars.join(', ')}`); + } + + console.log('✅ All required environment variables are set'); + console.log(`📋 Testing workspace: ${config.workspaceSlug}`); +}); + +// Global test timeout +jest.setTimeout(30000); + +// Suppress console.log during tests unless in verbose mode +if (!process.env.JEST_VERBOSE) { + global.console = { + ...console, + log: jest.fn(), + debug: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }; +} \ No newline at end of file diff --git a/tests/state.test.ts b/tests/unit/state.test.ts similarity index 100% rename from tests/state.test.ts rename to tests/unit/state.test.ts diff --git a/tests/test-utils.ts b/tests/unit/test-utils.ts similarity index 100% rename from tests/test-utils.ts rename to tests/unit/test-utils.ts diff --git a/tests/work-item-types/properties-options.test.ts b/tests/unit/work-item-types/properties-options.test.ts similarity index 100% rename from tests/work-item-types/properties-options.test.ts rename to tests/unit/work-item-types/properties-options.test.ts diff --git a/tests/work-item-types/properties-values.test.ts b/tests/unit/work-item-types/properties-values.test.ts similarity index 100% rename from tests/work-item-types/properties-values.test.ts rename to tests/unit/work-item-types/properties-values.test.ts diff --git a/tests/work-item-types/types.test.ts b/tests/unit/work-item-types/types.test.ts similarity index 100% rename from tests/work-item-types/types.test.ts rename to tests/unit/work-item-types/types.test.ts diff --git a/tests/work-items/activities.test.ts b/tests/unit/work-items/activities.test.ts similarity index 100% rename from tests/work-items/activities.test.ts rename to tests/unit/work-items/activities.test.ts diff --git a/tests/work-items/comments.test.ts b/tests/unit/work-items/comments.test.ts similarity index 100% rename from tests/work-items/comments.test.ts rename to tests/unit/work-items/comments.test.ts diff --git a/tests/work-items/links.test.ts b/tests/unit/work-items/links.test.ts similarity index 100% rename from tests/work-items/links.test.ts rename to tests/unit/work-items/links.test.ts diff --git a/tests/work-items/relations.test.ts b/tests/unit/work-items/relations.test.ts similarity index 100% rename from tests/work-items/relations.test.ts rename to tests/unit/work-items/relations.test.ts diff --git a/tests/work-items/work-items.test.ts b/tests/unit/work-items/work-items.test.ts similarity index 100% rename from tests/work-items/work-items.test.ts rename to tests/unit/work-items/work-items.test.ts diff --git a/tests/work-items/work-logs.test.ts b/tests/unit/work-items/work-logs.test.ts similarity index 100% rename from tests/work-items/work-logs.test.ts rename to tests/unit/work-items/work-logs.test.ts From f2ee039ca549358ab4d4f8183a8007f90b63ecbf Mon Sep 17 00:00:00 2001 From: Surya Prashanth Date: Tue, 28 Oct 2025 19:30:25 +0530 Subject: [PATCH 2/6] don't fail unit tests when env is not setup --- examples/README.md | 2 +- examples/bootstrap-project.ts | 15 +- package.json | 2 +- tests/unit/customers/customers.test.ts | 37 ++-- .../unit/customers/properties-options.test.ts | 144 +++++----------- tests/unit/customers/requests.test.ts | 95 +++------- tests/unit/customers/work-items.test.ts | 50 ++---- tests/unit/cycle.test.ts | 157 ++++------------- tests/unit/epic.test.ts | 23 +-- tests/unit/intake.test.ts | 65 +++---- tests/unit/label.test.ts | 61 ++----- tests/unit/module.test.ts | 107 +++--------- tests/unit/oauth.test.ts | 14 +- tests/unit/page.test.ts | 60 +++---- tests/unit/project.test.ts | 59 ++----- tests/unit/state.test.ts | 61 ++----- tests/unit/test-utils.ts | 3 +- .../properties-options.test.ts | 163 ++++++------------ .../work-item-types/properties-values.test.ts | 36 ++-- tests/unit/work-item-types/types.test.ts | 76 +++----- tests/unit/work-items/activities.test.ts | 42 ++--- tests/unit/work-items/comments.test.ts | 96 +++-------- tests/unit/work-items/links.test.ts | 86 +++------ tests/unit/work-items/relations.test.ts | 60 ++----- tests/unit/work-items/work-items.test.ts | 107 +++--------- tests/unit/work-items/work-logs.test.ts | 75 ++------ 26 files changed, 461 insertions(+), 1235 deletions(-) diff --git a/examples/README.md b/examples/README.md index 3abaddb..d889041 100644 --- a/examples/README.md +++ b/examples/README.md @@ -47,7 +47,7 @@ Sensitive information like API keys and authorization tokens are automatically r When adding new examples: 1. Create a new `.ts` file in this directory -2. Import the SDK: `import { PlaneClient } from '../src'` +2. Import the SDK: `import { PlaneClient } from '../../src'` 3. Include proper error handling 4. Add documentation comments 5. Update this README with a description diff --git a/examples/bootstrap-project.ts b/examples/bootstrap-project.ts index 9f97029..ec6dec8 100644 --- a/examples/bootstrap-project.ts +++ b/examples/bootstrap-project.ts @@ -1,5 +1,5 @@ // examples/project-bootstrap.ts -import { CreateWorkItemProperty, PlaneClient, WorkItemProperty } from "../src"; +import { CreateWorkItemProperty, PlaneClient, WorkItemProperty } from "../../src"; async function bootstrapProject(workspaceSlug: string) { const client = new PlaneClient({ @@ -30,11 +30,7 @@ async function bootstrapProject(workspaceSlug: string) { ]; for (const type of workItemTypes) { - const workItemType = await client.workItemTypes.create( - workspaceSlug, - project.id, - type - ); + const workItemType = await client.workItemTypes.create(workspaceSlug, project.id, type); const workItemTypeId = workItemType.id; const customProperties: CreateWorkItemProperty[] = [ { @@ -47,12 +43,7 @@ async function bootstrapProject(workspaceSlug: string) { ]; // 3. Create custom properties for (const prop of customProperties) { - await client.workItemProperties.create( - workspaceSlug, - project.id, - workItemTypeId, - prop - ); + await client.workItemProperties.create(workspaceSlug, project.id, workItemTypeId, prop); } } diff --git a/package.json b/package.json index 76062e5..e0112f0 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "scripts": { "build": "tsc", "dev": "tsc --watch", - "test": "ts-node tests/run-all.test.ts", + "test:unit": "ts-node tests/unit/run-all.test.ts", "lint": "eslint src/**/*.ts", "format": "prettier --write src/**/*.ts", "clean": "rm -rf dist" diff --git a/tests/unit/customers/customers.test.ts b/tests/unit/customers/customers.test.ts index 83a56db..1936e64 100644 --- a/tests/unit/customers/customers.test.ts +++ b/tests/unit/customers/customers.test.ts @@ -1,4 +1,4 @@ -import { PlaneClient } from "../../src/client/plane-client"; +import { PlaneClient } from "../../../src/client/plane-client"; import { config } from "../constants"; import { createTestClient } from "../test-utils"; @@ -7,21 +7,18 @@ export async function testCustomers() { const workspaceSlug = config.workspaceSlug; + if (!workspaceSlug) { + console.error("workspaceSlug is required"); + return; + } + const customer = await createCustomer(client, workspaceSlug); console.log("Created customer: ", customer); - const retrievedCustomer = await retrieveCustomer( - client, - workspaceSlug, - customer.id - ); + const retrievedCustomer = await retrieveCustomer(client, workspaceSlug, customer.id); console.log("Retrieved customer: ", retrievedCustomer); - const updatedCustomer = await updateCustomer( - client, - workspaceSlug, - customer.id - ); + const updatedCustomer = await updateCustomer(client, workspaceSlug, customer.id); console.log("Updated customer: ", updatedCustomer); const customers = await listCustomers(client, workspaceSlug); @@ -39,20 +36,12 @@ async function createCustomer(client: PlaneClient, workspaceSlug: string) { return customer; } -async function retrieveCustomer( - client: PlaneClient, - workspaceSlug: string, - customerId: string -) { +async function retrieveCustomer(client: PlaneClient, workspaceSlug: string, customerId: string) { const customer = await client.customers.retrieve(workspaceSlug, customerId); return customer; } -async function updateCustomer( - client: PlaneClient, - workspaceSlug: string, - customerId: string -) { +async function updateCustomer(client: PlaneClient, workspaceSlug: string, customerId: string) { return await client.customers.update(workspaceSlug, customerId, { name: `Updated Test Customer ${new Date().getTime()}`, description: "Updated Test Customer Description", @@ -67,11 +56,7 @@ async function listCustomers(client: PlaneClient, workspaceSlug: string) { return customers; } -async function deleteCustomer( - client: PlaneClient, - workspaceSlug: string, - customerId: string -) { +async function deleteCustomer(client: PlaneClient, workspaceSlug: string, customerId: string) { await client.customers.delete(workspaceSlug, customerId); } diff --git a/tests/unit/customers/properties-options.test.ts b/tests/unit/customers/properties-options.test.ts index e00cb01..cb8a2b4 100644 --- a/tests/unit/customers/properties-options.test.ts +++ b/tests/unit/customers/properties-options.test.ts @@ -1,4 +1,4 @@ -import { PlaneClient } from "../../src/client/plane-client"; +import { PlaneClient } from "../../../src/client/plane-client"; import { config } from "../constants"; import { createTestClient } from "../test-utils"; @@ -8,6 +8,11 @@ export async function testCustomersPropertiesOptionsAndValues() { const workspaceSlug = config.workspaceSlug; const customerId = config.customerId; + if (!workspaceSlug || !customerId) { + console.error("workspaceSlug and customerId are required"); + return; + } + const customerProperty = await createCustomerProperty(client, workspaceSlug); console.log("Created customer property: ", customerProperty); @@ -15,24 +20,13 @@ export async function testCustomersPropertiesOptionsAndValues() { throw new Error("Customer property ID is required"); } - const retrievedCustomerProperty = await retrieveCustomerProperty( - client, - workspaceSlug, - customerProperty.id - ); + const retrievedCustomerProperty = await retrieveCustomerProperty(client, workspaceSlug, customerProperty.id); console.log("Retrieved customer property: ", retrievedCustomerProperty); - const updatedCustomerProperty = await updateCustomerProperty( - client, - workspaceSlug, - customerProperty.id - ); + const updatedCustomerProperty = await updateCustomerProperty(client, workspaceSlug, customerProperty.id); console.log("Updated customer property: ", updatedCustomerProperty); - const customerProperties = await listCustomerProperties( - client, - workspaceSlug - ); + const customerProperties = await listCustomerProperties(client, workspaceSlug); console.log("Listed customer properties: ", customerProperties); // before deleting we test the property values @@ -42,19 +36,11 @@ export async function testCustomersPropertiesOptionsAndValues() { customerId, customerProperty.id ); - console.log( - "Updated customer property value: ", - customerProperty.id, - customerPropertyValue - ); + console.log("Updated customer property value: ", customerProperty.id, customerPropertyValue); await new Promise((resolve) => setTimeout(resolve, 1000)); - const allCustomerPropertyValues = await listCustomerPropertyValues( - client, - workspaceSlug, - customerId - ); + const allCustomerPropertyValues = await listCustomerPropertyValues(client, workspaceSlug, customerId); console.log("Listed customer property values: ", allCustomerPropertyValues); await new Promise((resolve) => setTimeout(resolve, 1000)); @@ -65,10 +51,7 @@ export async function testCustomersPropertiesOptionsAndValues() { customerId, customerProperty.id ); - console.log( - "Retrieved customer property value: ", - retrievedCustomerPropertyValue - ); + console.log("Retrieved customer property value: ", retrievedCustomerPropertyValue); await new Promise((resolve) => setTimeout(resolve, 1000)); @@ -77,70 +60,37 @@ export async function testCustomersPropertiesOptionsAndValues() { } // ===== CUSTOMER PROPERTY API METHODS ===== -async function createCustomerProperty( - client: PlaneClient, - workspaceSlug: string -) { - const customerProperty = - await client.customers.properties.createPropertyDefinition(workspaceSlug, { - name: `test-customer-property-${new Date().getTime()}`, - display_name: `Test Customer Property ${new Date().getTime()}`, - description: "Test Customer Property Description", - property_type: "TEXT", - }); +async function createCustomerProperty(client: PlaneClient, workspaceSlug: string) { + const customerProperty = await client.customers.properties.createPropertyDefinition(workspaceSlug, { + name: `test-customer-property-${new Date().getTime()}`, + display_name: `Test Customer Property ${new Date().getTime()}`, + description: "Test Customer Property Description", + property_type: "TEXT", + }); return customerProperty; } -async function retrieveCustomerProperty( - client: PlaneClient, - workspaceSlug: string, - propertyId: string -) { - const customerProperty = - await client.customers.properties.retrievePropertyDefinition( - workspaceSlug, - propertyId - ); +async function retrieveCustomerProperty(client: PlaneClient, workspaceSlug: string, propertyId: string) { + const customerProperty = await client.customers.properties.retrievePropertyDefinition(workspaceSlug, propertyId); return customerProperty; } -async function updateCustomerProperty( - client: PlaneClient, - workspaceSlug: string, - propertyId: string -) { - return await client.customers.properties.updatePropertyDefinition( - workspaceSlug, - propertyId, - { - display_name: `Updated Test Customer Property ${new Date().getTime()}`, - description: "Updated Test Customer Property Description", - } - ); +async function updateCustomerProperty(client: PlaneClient, workspaceSlug: string, propertyId: string) { + return await client.customers.properties.updatePropertyDefinition(workspaceSlug, propertyId, { + display_name: `Updated Test Customer Property ${new Date().getTime()}`, + description: "Updated Test Customer Property Description", + }); } -async function listCustomerProperties( - client: PlaneClient, - workspaceSlug: string -) { - return await client.customers.properties.listPropertyDefinitions( - workspaceSlug, - { - limit: 10, - offset: 0, - } - ); +async function listCustomerProperties(client: PlaneClient, workspaceSlug: string) { + return await client.customers.properties.listPropertyDefinitions(workspaceSlug, { + limit: 10, + offset: 0, + }); } -async function deleteCustomerProperty( - client: PlaneClient, - workspaceSlug: string, - propertyId: string -) { - return await client.customers.properties.deletePropertyDefinition( - workspaceSlug, - propertyId - ); +async function deleteCustomerProperty(client: PlaneClient, workspaceSlug: string, propertyId: string) { + return await client.customers.properties.deletePropertyDefinition(workspaceSlug, propertyId); } // ===== CUSTOMER PROPERTY VALUES API METHODS ===== @@ -150,25 +100,13 @@ async function updateCustomerPropertyValue( customerId: string, propertyId: string ) { - return await client.customers.properties.updateValue( - workspaceSlug, - customerId, - propertyId, - { - values: ["Property Value Updated"], - } - ); + return await client.customers.properties.updateValue(workspaceSlug, customerId, propertyId, { + values: ["Property Value Updated"], + }); } -async function listCustomerPropertyValues( - client: PlaneClient, - workspaceSlug: string, - customerId: string -) { - return await client.customers.properties.listValues( - workspaceSlug, - customerId - ); +async function listCustomerPropertyValues(client: PlaneClient, workspaceSlug: string, customerId: string) { + return await client.customers.properties.listValues(workspaceSlug, customerId); } async function retrieveCustomerPropertyValue( @@ -177,11 +115,7 @@ async function retrieveCustomerPropertyValue( customerId: string, propertyId: string ) { - return await client.customers.properties.retrieveValue( - workspaceSlug, - customerId, - propertyId - ); + return await client.customers.properties.retrieveValue(workspaceSlug, customerId, propertyId); } if (require.main === module) { diff --git a/tests/unit/customers/requests.test.ts b/tests/unit/customers/requests.test.ts index 1c70ff4..fc1bf6c 100644 --- a/tests/unit/customers/requests.test.ts +++ b/tests/unit/customers/requests.test.ts @@ -1,4 +1,4 @@ -import { PlaneClient } from "../../src/client/plane-client"; +import { PlaneClient } from "../../../src/client/plane-client"; import { config } from "../constants"; import { createTestClient } from "../test-utils"; @@ -8,58 +8,32 @@ export async function testCustomersRequests() { const workspaceSlug = config.workspaceSlug; const customerId = config.customerId; - const customerRequest = await createCustomerRequest( - client, - workspaceSlug, - customerId - ); + if (!workspaceSlug || !customerId) { + console.error("workspaceSlug and customerId are required"); + return; + } + + const customerRequest = await createCustomerRequest(client, workspaceSlug, customerId); console.log("Created customer request: ", customerRequest); - const retrievedCustomerRequest = await retrieveCustomerRequest( - client, - workspaceSlug, - customerId, - customerRequest.id - ); + const retrievedCustomerRequest = await retrieveCustomerRequest(client, workspaceSlug, customerId, customerRequest.id); console.log("Retrieved customer request: ", retrievedCustomerRequest); - const updatedCustomerRequest = await updateCustomerRequest( - client, - workspaceSlug, - customerId, - customerRequest.id - ); + const updatedCustomerRequest = await updateCustomerRequest(client, workspaceSlug, customerId, customerRequest.id); console.log("Updated customer request: ", updatedCustomerRequest); - const customerRequests = await listCustomerRequests( - client, - workspaceSlug, - customerId - ); + const customerRequests = await listCustomerRequests(client, workspaceSlug, customerId); console.log("Listed customer requests: ", customerRequests); - await deleteCustomerRequest( - client, - workspaceSlug, - customerId, - customerRequest.id - ); + await deleteCustomerRequest(client, workspaceSlug, customerId, customerRequest.id); console.log("Deleted customer request: ", customerRequest.id); } -async function createCustomerRequest( - client: PlaneClient, - workspaceSlug: string, - customerId: string -) { - const customerRequest = await client.customers.requests.create( - workspaceSlug, - customerId, - { - name: `Test Customer Request ${new Date().getTime()}`, - description: "Test Customer Request Description", - } - ); +async function createCustomerRequest(client: PlaneClient, workspaceSlug: string, customerId: string) { + const customerRequest = await client.customers.requests.create(workspaceSlug, customerId, { + name: `Test Customer Request ${new Date().getTime()}`, + description: "Test Customer Request Description", + }); return customerRequest; } @@ -69,11 +43,7 @@ async function retrieveCustomerRequest( customerId: string, requestId: string ) { - const customerRequest = await client.customers.requests.retrieve( - workspaceSlug, - customerId, - requestId - ); + const customerRequest = await client.customers.requests.retrieve(workspaceSlug, customerId, requestId); return customerRequest; } @@ -83,30 +53,17 @@ async function updateCustomerRequest( customerId: string, requestId: string ) { - return await client.customers.requests.update( - workspaceSlug, - customerId, - requestId, - { - name: `Updated Test Customer Request ${new Date().getTime()}`, - description: "Updated Test Customer Request Description", - } - ); + return await client.customers.requests.update(workspaceSlug, customerId, requestId, { + name: `Updated Test Customer Request ${new Date().getTime()}`, + description: "Updated Test Customer Request Description", + }); } -async function listCustomerRequests( - client: PlaneClient, - workspaceSlug: string, - customerId: string -) { - const customerRequests = await client.customers.requests.list( - workspaceSlug, - customerId, - { - limit: 10, - offset: 0, - } - ); +async function listCustomerRequests(client: PlaneClient, workspaceSlug: string, customerId: string) { + const customerRequests = await client.customers.requests.list(workspaceSlug, customerId, { + limit: 10, + offset: 0, + }); return customerRequests; } diff --git a/tests/unit/customers/work-items.test.ts b/tests/unit/customers/work-items.test.ts index ef63d13..585468d 100644 --- a/tests/unit/customers/work-items.test.ts +++ b/tests/unit/customers/work-items.test.ts @@ -1,4 +1,4 @@ -import { PlaneClient } from "../../src/client/plane-client"; +import { PlaneClient } from "../../../src/client/plane-client"; import { config } from "../constants"; import { createTestClient } from "../test-utils"; @@ -9,27 +9,18 @@ export async function testCustomersWorkItems() { const customerId = config.customerId; const workItemId = config.workItemId; - const customer = await linkWorkItemsToCustomer( - client, - workspaceSlug, - customerId, - [workItemId] - ); + if (!workspaceSlug || !customerId || !workItemId) { + console.error("workspaceSlug, customerId and workItemId are required"); + return; + } + + const customer = await linkWorkItemsToCustomer(client, workspaceSlug, customerId, [workItemId]); console.log("Linked work items to customer: ", customer); - const retrievedCustomerWorkItems = await listCustomerWorkItems( - client, - workspaceSlug, - customerId - ); + const retrievedCustomerWorkItems = await listCustomerWorkItems(client, workspaceSlug, customerId); console.log("Retrieved customer work items: ", retrievedCustomerWorkItems); - const updatedCustomer = await unlinkWorkItemFromCustomer( - client, - workspaceSlug, - customerId, - workItemId - ); + const updatedCustomer = await unlinkWorkItemFromCustomer(client, workspaceSlug, customerId, workItemId); console.log("Unlinked work item from customer: ", updatedCustomer); } @@ -39,23 +30,12 @@ async function linkWorkItemsToCustomer( customerId: string, issueIds: string[] ) { - const customer = await client.customers.linkIssuesToCustomer( - workspaceSlug, - customerId, - issueIds - ); + const customer = await client.customers.linkIssuesToCustomer(workspaceSlug, customerId, issueIds); return customer; } -async function listCustomerWorkItems( - client: PlaneClient, - workspaceSlug: string, - customerId: string -) { - const customer = await client.customers.listCustomerIssues( - workspaceSlug, - customerId - ); +async function listCustomerWorkItems(client: PlaneClient, workspaceSlug: string, customerId: string) { + const customer = await client.customers.listCustomerIssues(workspaceSlug, customerId); return customer; } @@ -65,11 +45,7 @@ async function unlinkWorkItemFromCustomer( customerId: string, issueId: string ) { - return await client.customers.unlinkIssueFromCustomer( - workspaceSlug, - customerId, - issueId - ); + return await client.customers.unlinkIssueFromCustomer(workspaceSlug, customerId, issueId); } if (require.main === module) { diff --git a/tests/unit/cycle.test.ts b/tests/unit/cycle.test.ts index d9d256b..a54c8c5 100644 --- a/tests/unit/cycle.test.ts +++ b/tests/unit/cycle.test.ts @@ -1,5 +1,5 @@ -import { PlaneClient } from "../src/client/plane-client"; -import { UpdateCycleRequest } from "../src/models/Cycle"; +import { PlaneClient } from "../../src/client/plane-client"; +import { UpdateCycleRequest } from "../../src/models/Cycle"; import { config } from "./constants"; import { createTestClient } from "./test-utils"; @@ -10,6 +10,11 @@ export async function testCycles() { const projectId = config.projectId; const workItemId = config.workItemId; + if (!workspaceSlug || !projectId || !workItemId) { + console.error("workspaceSlug, projectId and workItemId are required"); + return; + } + const project = await client.projects.retrieve(workspaceSlug, projectId); if (!project.cycle_view) { await client.projects.update(workspaceSlug, projectId, { @@ -21,25 +26,14 @@ export async function testCycles() { console.log("Created cycle: ", cycle); await new Promise((resolve) => setTimeout(resolve, 1000)); - const retrievedCycle = await retrieveCycle( - client, - workspaceSlug, - projectId, - cycle.id - ); + const retrievedCycle = await retrieveCycle(client, workspaceSlug, projectId, cycle.id); console.log("Retrieved cycle: ", retrievedCycle); await new Promise((resolve) => setTimeout(resolve, 1000)); - const updatedCycle = await updateCycle( - client, - workspaceSlug, - projectId, - cycle.id, - { - name: "Updated Test Cycle", - description: "Updated Test Cycle Description", - } - ); + const updatedCycle = await updateCycle(client, workspaceSlug, projectId, cycle.id, { + name: "Updated Test Cycle", + description: "Updated Test Cycle Description", + }); console.log("Updated cycle: ", updatedCycle); await new Promise((resolve) => setTimeout(resolve, 1000)); @@ -47,32 +41,15 @@ export async function testCycles() { console.log("Listed cycles: ", cycles); await new Promise((resolve) => setTimeout(resolve, 1000)); - await addWorkItemsToCycle( - client, - workspaceSlug, - projectId, - cycle.id, - workItemId - ); + await addWorkItemsToCycle(client, workspaceSlug, projectId, cycle.id, workItemId); console.log("Added work item to cycle: ", workItemId); await new Promise((resolve) => setTimeout(resolve, 1000)); - const itemsInCycle = await listWorkItemsInCycle( - client, - workspaceSlug, - projectId, - cycle.id - ); + const itemsInCycle = await listWorkItemsInCycle(client, workspaceSlug, projectId, cycle.id); console.log("Listed work items in cycle: ", itemsInCycle); await new Promise((resolve) => setTimeout(resolve, 1000)); - const removedItem = await removeWorkItemFromCycle( - client, - workspaceSlug, - projectId, - cycle.id, - workItemId - ); + const removedItem = await removeWorkItemFromCycle(client, workspaceSlug, projectId, cycle.id, workItemId); console.log("Removed work item from cycle: ", removedItem); await new Promise((resolve) => setTimeout(resolve, 1000)); @@ -89,23 +66,11 @@ export async function testCycles() { await new Promise((resolve) => setTimeout(resolve, 1000)); // Add work item back to first cycle for transfer test - await addWorkItemsToCycle( - client, - workspaceSlug, - projectId, - cycle.id, - workItemId - ); + await addWorkItemsToCycle(client, workspaceSlug, projectId, cycle.id, workItemId); console.log("Re-added work item to first cycle: ", workItemId); await new Promise((resolve) => setTimeout(resolve, 1000)); - await transferWorkItemsToAnotherCycle( - client, - workspaceSlug, - projectId, - cycle.id, - cycle2.id - ); + await transferWorkItemsToAnotherCycle(client, workspaceSlug, projectId, cycle.id, cycle2.id); console.log("Transferred work items to another cycle"); await new Promise((resolve) => setTimeout(resolve, 1000)); @@ -133,11 +98,7 @@ export async function testCycles() { console.log("Deleted second cycle: ", cycle2.id); } -async function createCycle( - client: PlaneClient, - workspaceSlug: string, - projectId: string -) { +async function createCycle(client: PlaneClient, workspaceSlug: string, projectId: string) { return await client.cycles.create(workspaceSlug, projectId, { name: "Test Cycle", description: "Test Cycle Description", @@ -145,12 +106,7 @@ async function createCycle( }); } -async function retrieveCycle( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - cycleId: string -) { +async function retrieveCycle(client: PlaneClient, workspaceSlug: string, projectId: string, cycleId: string) { return await client.cycles.retrieve(workspaceSlug, projectId, cycleId); } @@ -164,20 +120,11 @@ async function updateCycle( return await client.cycles.update(workspaceSlug, projectId, cycleId, cycle); } -async function listCycles( - client: PlaneClient, - workspaceSlug: string, - projectId: string -) { +async function listCycles(client: PlaneClient, workspaceSlug: string, projectId: string) { return await client.cycles.list(workspaceSlug, projectId); } -async function deleteCycle( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - cycleId: string -) { +async function deleteCycle(client: PlaneClient, workspaceSlug: string, projectId: string, cycleId: string) { return await client.cycles.delete(workspaceSlug, projectId, cycleId); } @@ -188,25 +135,11 @@ async function addWorkItemsToCycle( cycleId: string, workItemId: string ) { - return await client.cycles.addWorkItemsToCycle( - workspaceSlug, - projectId, - cycleId, - [workItemId] - ); + return await client.cycles.addWorkItemsToCycle(workspaceSlug, projectId, cycleId, [workItemId]); } -async function listWorkItemsInCycle( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - cycleId: string -) { - return await client.cycles.listWorkItemsInCycle( - workspaceSlug, - projectId, - cycleId - ); +async function listWorkItemsInCycle(client: PlaneClient, workspaceSlug: string, projectId: string, cycleId: string) { + return await client.cycles.listWorkItemsInCycle(workspaceSlug, projectId, cycleId); } async function removeWorkItemFromCycle( @@ -216,12 +149,7 @@ async function removeWorkItemFromCycle( cycleId: string, workItemId: string ) { - return await client.cycles.removeWorkItemFromCycle( - workspaceSlug, - projectId, - cycleId, - workItemId - ); + return await client.cycles.removeWorkItemFromCycle(workspaceSlug, projectId, cycleId, workItemId); } async function transferWorkItemsToAnotherCycle( @@ -231,37 +159,20 @@ async function transferWorkItemsToAnotherCycle( cycleId: string, newCycleId: string ) { - return await client.cycles.transferWorkItemsToAnotherCycle( - workspaceSlug, - projectId, - cycleId, - { new_cycle_id: newCycleId } - ); + return await client.cycles.transferWorkItemsToAnotherCycle(workspaceSlug, projectId, cycleId, { + new_cycle_id: newCycleId, + }); } -async function archiveCycle( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - cycleId: string -) { +async function archiveCycle(client: PlaneClient, workspaceSlug: string, projectId: string, cycleId: string) { return await client.cycles.archive(workspaceSlug, projectId, cycleId); } -async function listArchivedCycles( - client: PlaneClient, - workspaceSlug: string, - projectId: string -) { +async function listArchivedCycles(client: PlaneClient, workspaceSlug: string, projectId: string) { return await client.cycles.listArchived(workspaceSlug, projectId); } -async function unArchiveCycle( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - cycleId: string -) { +async function unArchiveCycle(client: PlaneClient, workspaceSlug: string, projectId: string, cycleId: string) { return await client.cycles.unArchive(workspaceSlug, projectId, cycleId); } @@ -277,11 +188,7 @@ async function justArchiveCycle() { }); } - return await client.cycles.archive( - workspaceSlug, - projectId, - "e1ca5ee2-c968-4be5-80fa-f6dff66bea98" - ); + return await client.cycles.archive(workspaceSlug, projectId, "e1ca5ee2-c968-4be5-80fa-f6dff66bea98"); } if (require.main === module) { diff --git a/tests/unit/epic.test.ts b/tests/unit/epic.test.ts index 3c6218e..0d347a5 100644 --- a/tests/unit/epic.test.ts +++ b/tests/unit/epic.test.ts @@ -1,24 +1,25 @@ -import { PlaneClient } from "../src/client/plane-client"; +import { PlaneClient } from "../../src/client/plane-client"; import { config } from "./constants"; import { createTestClient } from "./test-utils"; export async function testEpics() { const client = createTestClient(); - const project = await client.projects.retrieve( - config.workspaceSlug, - config.projectId - ); + const workspaceSlug = config.workspaceSlug; + const projectId = config.projectId; - const epics = await client.epics.list(config.workspaceSlug, config.projectId); + if (!workspaceSlug || !projectId) { + console.error("workspaceSlug and projectId are required"); + return; + } + + const project = await client.projects.retrieve(workspaceSlug, projectId); + + const epics = await client.epics.list(workspaceSlug, projectId); console.log("Listed epics: ", epics); - const epic = await client.epics.retrieve( - config.workspaceSlug, - config.projectId, - epics.results[0]!.id! - ); + const epic = await client.epics.retrieve(workspaceSlug, projectId, epics.results[0]!.id!); console.log("Retrieved epic: ", epic); } diff --git a/tests/unit/intake.test.ts b/tests/unit/intake.test.ts index 30d1f3b..2ee2ce8 100644 --- a/tests/unit/intake.test.ts +++ b/tests/unit/intake.test.ts @@ -1,6 +1,6 @@ -import { PlaneClient } from "../src/client/plane-client"; -import { PaginatedResponse } from "../src/models/common"; -import { IntakeWorkItem } from "../src/models/Intake"; +import { PlaneClient } from "../../src/client/plane-client"; +import { PaginatedResponse } from "../../src/models/common"; +import { IntakeWorkItem } from "../../src/models/Intake"; import { config } from "./constants"; import { createTestClient } from "./test-utils"; @@ -10,33 +10,23 @@ export async function testIntake() { const workspaceSlug = config.workspaceSlug; const projectId = config.projectId; + if (!workspaceSlug || !projectId) { + console.error("workspaceSlug and projectId are required"); + return; + } + // enable intake if didn't already - const updatedProject = await client.projects.update( - workspaceSlug, - projectId, - { - intake_view: true, - } - ); + const updatedProject = await client.projects.update(workspaceSlug, projectId, { + intake_view: true, + }); const intakeWorkItem = await createIntake(client, workspaceSlug, projectId); console.log("Created intake: ", intakeWorkItem); - const retrievedIntake = await retrieveIntake( - client, - workspaceSlug, - projectId, - intakeWorkItem.issue! - ); + const retrievedIntake = await retrieveIntake(client, workspaceSlug, projectId, intakeWorkItem.issue!); console.log("Retrieved intake: ", retrievedIntake); - const updatedIntake = await updateIntake( - client, - workspaceSlug, - projectId, - intakeWorkItem.issue!, - intakeWorkItem - ); + const updatedIntake = await updateIntake(client, workspaceSlug, projectId, intakeWorkItem.issue!, intakeWorkItem); console.log("Updated intake: ", updatedIntake); const intakes = await listIntake(client, workspaceSlug, projectId); @@ -46,11 +36,7 @@ export async function testIntake() { console.log("Intake deleted: ", intakeWorkItem.id); } -async function createIntake( - client: PlaneClient, - workspaceSlug: string, - projectId: string -): Promise { +async function createIntake(client: PlaneClient, workspaceSlug: string, projectId: string): Promise { const intake = await client.intake.create(workspaceSlug, projectId, { issue: { name: "Test Intake", @@ -66,11 +52,7 @@ async function retrieveIntake( projectId: string, intakeWorkItemId: string ): Promise { - const intake = await client.intake.retrieve( - workspaceSlug, - projectId, - intakeWorkItemId - ); + const intake = await client.intake.retrieve(workspaceSlug, projectId, intakeWorkItemId); return intake; } @@ -90,17 +72,12 @@ async function updateIntake( intakeWorkItemId: string, intake: IntakeWorkItem ): Promise { - const updatedIntake = await client.intake.update( - workspaceSlug, - projectId, - intakeWorkItemId, - { - issue: { - name: "Updated Test Intake", - description_html: "

Updated Test Intake Description

", - }, - } - ); + const updatedIntake = await client.intake.update(workspaceSlug, projectId, intakeWorkItemId, { + issue: { + name: "Updated Test Intake", + description_html: "

Updated Test Intake Description

", + }, + }); return updatedIntake; } diff --git a/tests/unit/label.test.ts b/tests/unit/label.test.ts index 0866399..bc6dc22 100644 --- a/tests/unit/label.test.ts +++ b/tests/unit/label.test.ts @@ -1,5 +1,5 @@ -import { PlaneClient } from "../src/client/plane-client"; -import { Label } from "../src/models/Label"; +import { PlaneClient } from "../../src/client/plane-client"; +import { Label } from "../../src/models/Label"; import { config } from "./constants"; import { createTestClient } from "./test-utils"; @@ -9,24 +9,18 @@ export async function testLabels() { const workspaceSlug = config.workspaceSlug; const projectId = config.projectId; + if (!workspaceSlug || !projectId) { + console.error("workspaceSlug and projectId are required"); + return; + } + const labelObj = await createLabel(client, workspaceSlug, projectId); console.log("Created label: ", labelObj); - const retrievedLabel = await retrieveLabel( - client, - workspaceSlug, - projectId, - labelObj.id - ); + const retrievedLabel = await retrieveLabel(client, workspaceSlug, projectId, labelObj.id); console.log("Retrieved label: ", retrievedLabel); - const updatedLabel = await updateLabel( - client, - workspaceSlug, - projectId, - labelObj.id, - labelObj - ); + const updatedLabel = await updateLabel(client, workspaceSlug, projectId, labelObj.id, labelObj); console.log("Updated label: ", updatedLabel); const labels = await listLabels(client, workspaceSlug, projectId); @@ -36,11 +30,7 @@ export async function testLabels() { console.log("Label deleted: ", labelObj.id); } -async function createLabel( - client: PlaneClient, - workspaceSlug: string, - projectId: string -) { +async function createLabel(client: PlaneClient, workspaceSlug: string, projectId: string) { const label = await client.labels.create(workspaceSlug, projectId, { name: "Test Label " + new Date().getTime(), description: "Test Label Description", @@ -48,12 +38,7 @@ async function createLabel( return label; } -async function retrieveLabel( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - labelId: string -) { +async function retrieveLabel(client: PlaneClient, workspaceSlug: string, projectId: string, labelId: string) { const label = await client.labels.retrieve(workspaceSlug, projectId, labelId); return label; } @@ -65,31 +50,17 @@ async function updateLabel( labelId: string, label: Label ) { - const updatedLabel = await client.labels.update( - workspaceSlug, - projectId, - labelId, - { - description: "Updated Test Label Description" + new Date().toISOString(), - } - ); + const updatedLabel = await client.labels.update(workspaceSlug, projectId, labelId, { + description: "Updated Test Label Description" + new Date().toISOString(), + }); return updatedLabel; } -async function deleteLabel( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - labelId: string -) { +async function deleteLabel(client: PlaneClient, workspaceSlug: string, projectId: string, labelId: string) { await client.labels.delete(workspaceSlug, projectId, labelId); } -async function listLabels( - client: PlaneClient, - workspaceSlug: string, - projectId: string -) { +async function listLabels(client: PlaneClient, workspaceSlug: string, projectId: string) { const labels = await client.labels.list(workspaceSlug, projectId); return labels; } diff --git a/tests/unit/module.test.ts b/tests/unit/module.test.ts index faecad3..7049f65 100644 --- a/tests/unit/module.test.ts +++ b/tests/unit/module.test.ts @@ -1,5 +1,5 @@ -import { PlaneClient } from "../src/client/plane-client"; -import { UpdateModuleRequest } from "../src/models/Module"; +import { PlaneClient } from "../../src/client/plane-client"; +import { UpdateModuleRequest } from "../../src/models/Module"; import { config } from "./constants"; import { createTestClient } from "./test-utils"; @@ -10,26 +10,20 @@ export async function testModules() { const projectId = config.projectId; const workItemId = config.workItemId; + if (!workspaceSlug || !projectId || !workItemId) { + console.error("workspaceSlug, projectId and workItemId are required"); + return; + } + const module = await createModule(client, workspaceSlug, projectId); console.log("Created module: ", module); await new Promise((resolve) => setTimeout(resolve, 1000)); - const retrievedModule = await retrieveModule( - client, - workspaceSlug, - projectId, - module.id - ); + const retrievedModule = await retrieveModule(client, workspaceSlug, projectId, module.id); console.log("Retrieved module: ", retrievedModule); await new Promise((resolve) => setTimeout(resolve, 1000)); - const updatedModule = await updateModule( - client, - workspaceSlug, - projectId, - module.id, - module - ); + const updatedModule = await updateModule(client, workspaceSlug, projectId, module.id, module); console.log("Updated module: ", updatedModule); await new Promise((resolve) => setTimeout(resolve, 1000)); @@ -37,32 +31,15 @@ export async function testModules() { console.log("Listed modules: ", modules); await new Promise((resolve) => setTimeout(resolve, 1000)); - await addWorkItemToModule( - client, - workspaceSlug, - projectId, - module.id, - workItemId - ); + await addWorkItemToModule(client, workspaceSlug, projectId, module.id, workItemId); console.log("Added work item to module: ", workItemId); await new Promise((resolve) => setTimeout(resolve, 1000)); - const itemsInModule = await listWorkItemsInModule( - client, - workspaceSlug, - projectId, - module.id - ); + const itemsInModule = await listWorkItemsInModule(client, workspaceSlug, projectId, module.id); console.log("Listed work items in module: ", itemsInModule); await new Promise((resolve) => setTimeout(resolve, 1000)); - const removedItem = await removeWorkItemFromModule( - client, - workspaceSlug, - projectId, - module.id, - workItemId - ); + const removedItem = await removeWorkItemFromModule(client, workspaceSlug, projectId, module.id, workItemId); console.log("Removed work item from module: ", removedItem); await new Promise((resolve) => setTimeout(resolve, 1000)); @@ -70,23 +47,14 @@ export async function testModules() { console.log("Deleted module: ", module.id); } -async function createModule( - client: PlaneClient, - workspaceSlug: string, - projectId: string -) { +async function createModule(client: PlaneClient, workspaceSlug: string, projectId: string) { return await client.modules.create(workspaceSlug, projectId, { name: "Test Module", description: "Test Description", }); } -async function retrieveModule( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - moduleId: string -) { +async function retrieveModule(client: PlaneClient, workspaceSlug: string, projectId: string, moduleId: string) { return await client.modules.retrieve(workspaceSlug, projectId, moduleId); } @@ -97,28 +65,14 @@ async function updateModule( moduleId: string, module: UpdateModuleRequest ) { - return await client.modules.update( - workspaceSlug, - projectId, - moduleId, - module - ); + return await client.modules.update(workspaceSlug, projectId, moduleId, module); } -async function listModules( - client: PlaneClient, - workspaceSlug: string, - projectId: string -) { +async function listModules(client: PlaneClient, workspaceSlug: string, projectId: string) { return await client.modules.list(workspaceSlug, projectId); } -async function deleteModule( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - moduleId: string -) { +async function deleteModule(client: PlaneClient, workspaceSlug: string, projectId: string, moduleId: string) { return await client.modules.delete(workspaceSlug, projectId, moduleId); } @@ -129,24 +83,10 @@ async function addWorkItemToModule( moduleId: string, workItemId: string ) { - return await client.modules.addWorkItemToModule( - workspaceSlug, - projectId, - moduleId, - [workItemId] - ); + return await client.modules.addWorkItemToModule(workspaceSlug, projectId, moduleId, [workItemId]); } -async function listWorkItemsInModule( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - moduleId: string -) { - return await client.modules.listWorkItemsInModule( - workspaceSlug, - projectId, - moduleId - ); +async function listWorkItemsInModule(client: PlaneClient, workspaceSlug: string, projectId: string, moduleId: string) { + return await client.modules.listWorkItemsInModule(workspaceSlug, projectId, moduleId); } async function removeWorkItemFromModule( @@ -156,12 +96,7 @@ async function removeWorkItemFromModule( moduleId: string, workItemId: string ) { - return await client.modules.removeWorkItemFromModule( - workspaceSlug, - projectId, - moduleId, - workItemId - ); + return await client.modules.removeWorkItemFromModule(workspaceSlug, projectId, moduleId, workItemId); } if (require.main === module) { diff --git a/tests/unit/oauth.test.ts b/tests/unit/oauth.test.ts index 88cd971..d4b5524 100644 --- a/tests/unit/oauth.test.ts +++ b/tests/unit/oauth.test.ts @@ -1,6 +1,6 @@ -import { PlaneClient } from "../src/client/plane-client"; -import { OAuthClient } from "../src/client/oauth-client"; -import { Configuration } from "../src/Configuration"; +import { PlaneClient } from "../../src/client/plane-client"; +import { OAuthClient } from "../../src/client/oauth-client"; +import { Configuration } from "../../src/Configuration"; /** * Test OAuth functionality with both standalone and integrated approaches @@ -33,15 +33,11 @@ export async function testOAuth() { const authUrl = oauthClient.getAuthorizationUrl(); console.log(" ✅ Authorization URL generated:", authUrl); - const botToken = await oauthClient.getBotToken( - process.env.PLANE_APP_INSTALLATION_ID! - ); + const botToken = await oauthClient.getBotToken(process.env.PLANE_APP_INSTALLATION_ID!); console.log(" ✅ Bot token generated:", botToken); - const installations = await oauthClient.getAppInstallations( - botToken.access_token - ); + const installations = await oauthClient.getAppInstallations(botToken.access_token); console.log(" ✅ App installations generated:", installations); diff --git a/tests/unit/page.test.ts b/tests/unit/page.test.ts index b360aa6..762c86a 100644 --- a/tests/unit/page.test.ts +++ b/tests/unit/page.test.ts @@ -1,34 +1,34 @@ import fs from "fs"; -import { PlaneClient } from "../src/client/plane-client"; +import { PlaneClient } from "../../src/client/plane-client"; import { config } from "./constants"; import { createTestClient } from "./test-utils"; export async function testPage() { const client = createTestClient(); - const page = await createPage(client, config.workspaceSlug); + const workspaceSlug = config.workspaceSlug; + const projectId = config.projectId; + + if (!workspaceSlug) { + console.error("workspaceSlug is required"); + return; + } + + if (!projectId) { + console.error("projectId is required"); + return; + } + + const page = await createPage(client, workspaceSlug); console.log("Created page: ", page); - const retrievedPage = await retrievePage( - client, - config.workspaceSlug, - page.id - ); + const retrievedPage = await retrievePage(client, workspaceSlug, page.id); console.log("Retrieved page: ", retrievedPage); - const projectPage = await createProjectPage( - client, - config.workspaceSlug, - config.projectId - ); + const projectPage = await createProjectPage(client, workspaceSlug, projectId); console.log("Created project page: ", projectPage); - const retrievedProjectPage = await retrieveProjectPage( - client, - config.workspaceSlug, - config.projectId, - projectPage.id - ); + const retrievedProjectPage = await retrieveProjectPage(client, workspaceSlug, projectId, projectPage.id); console.log("Retrieved project page: ", retrievedProjectPage); } @@ -40,19 +40,11 @@ async function createPage(client: PlaneClient, workspaceSlug: string) { }); } -async function retrievePage( - client: PlaneClient, - workspaceSlug: string, - pageId: string -) { +async function retrievePage(client: PlaneClient, workspaceSlug: string, pageId: string) { return client.pages.retrieveWorkspacePage(workspaceSlug, pageId); } -async function createProjectPage( - client: PlaneClient, - workspaceSlug: string, - projectId: string -) { +async function createProjectPage(client: PlaneClient, workspaceSlug: string, projectId: string) { const content = "

Blank Space

"; return client.pages.createProjectPage(workspaceSlug, projectId, { name: "Test Page Crashable 3", @@ -60,12 +52,7 @@ async function createProjectPage( }); } -async function retrieveProjectPage( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - pageId: string -) { +async function retrieveProjectPage(client: PlaneClient, workspaceSlug: string, projectId: string, pageId: string) { return client.pages.retrieveProjectPage(workspaceSlug, projectId, pageId); } @@ -76,10 +63,7 @@ async function testCreatePageFromFile() { enableLogging: true, }); - const file = fs.readFileSync( - "/Users/prashantsurya/Projects/sdks/plane-node-sdk/CrashablePage.html", - "utf8" - ); + const file = fs.readFileSync("/Users/prashantsurya/Projects/sdks/plane-node-sdk/CrashablePage.html", "utf8"); const page = await client.pages.createWorkspacePage("testt", { name: "Test Page Crashable 3", diff --git a/tests/unit/project.test.ts b/tests/unit/project.test.ts index 27a9ad2..dbc0af4 100644 --- a/tests/unit/project.test.ts +++ b/tests/unit/project.test.ts @@ -1,5 +1,5 @@ -import { PlaneClient } from "../src/client/plane-client"; -import { UpdateProject } from "../src/models/Project"; +import { PlaneClient } from "../../src/client/plane-client"; +import { UpdateProject } from "../../src/models/Project"; import { config } from "./constants"; import { createTestClient } from "./test-utils"; @@ -8,25 +8,21 @@ export async function testProjects() { const workspaceSlug = config.workspaceSlug; + if (!workspaceSlug) { + console.error("workspaceSlug is required"); + return; + } + const project = await createProject(client, workspaceSlug); console.log("created project", project); - const retrievedProject = await retrieveProject( - client, - workspaceSlug, - project.id - ); + const retrievedProject = await retrieveProject(client, workspaceSlug, project.id); console.log("retrieved project", retrievedProject); - const updatedProject = await updateProject( - client, - workspaceSlug, - project.id, - { - name: "Updated Test Project", - description: "Updated Test Project Description", - } - ); + const updatedProject = await updateProject(client, workspaceSlug, project.id, { + name: "Updated Test Project", + description: "Updated Test Project Description", + }); console.log("updated project", updatedProject); const projects = await listProjects(client, workspaceSlug); @@ -47,26 +43,13 @@ async function createProject(client: PlaneClient, workspaceSlug: string) { return project; } -async function retrieveProject( - client: PlaneClient, - workspaceSlug: string, - projectId: string -) { +async function retrieveProject(client: PlaneClient, workspaceSlug: string, projectId: string) { const project = await client.projects.retrieve(workspaceSlug, projectId); return project; } -async function updateProject( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - project: UpdateProject -) { - const updatedProject = await client.projects.update( - workspaceSlug, - projectId, - project - ); +async function updateProject(client: PlaneClient, workspaceSlug: string, projectId: string, project: UpdateProject) { + const updatedProject = await client.projects.update(workspaceSlug, projectId, project); return updatedProject; } @@ -75,20 +58,12 @@ async function listProjects(client: PlaneClient, workspaceSlug: string) { return projects; } -async function getMembers( - client: PlaneClient, - workspaceSlug: string, - projectId: string -) { +async function getMembers(client: PlaneClient, workspaceSlug: string, projectId: string) { const members = await client.projects.getMembers(workspaceSlug, projectId); return members; } -async function deleteProject( - client: PlaneClient, - workspaceSlug: string, - projectId: string -) { +async function deleteProject(client: PlaneClient, workspaceSlug: string, projectId: string) { await client.projects.delete(workspaceSlug, projectId); } diff --git a/tests/unit/state.test.ts b/tests/unit/state.test.ts index 57763f6..8b5f83d 100644 --- a/tests/unit/state.test.ts +++ b/tests/unit/state.test.ts @@ -1,5 +1,5 @@ -import { PlaneClient } from "../src/client/plane-client"; -import { State } from "../src/models/State"; +import { PlaneClient } from "../../src/client/plane-client"; +import { State } from "../../src/models/State"; import { config } from "./constants"; import { createTestClient } from "./test-utils"; @@ -9,24 +9,18 @@ export async function testStates() { const workspaceSlug = config.workspaceSlug; const projectId = config.projectId; + if (!workspaceSlug || !projectId) { + console.error("workspaceSlug and projectId are required"); + return; + } + const stateObj = await createState(client, workspaceSlug, projectId); console.log("Created state: ", stateObj); - const retrievedState = await retrieveState( - client, - workspaceSlug, - projectId, - stateObj.id - ); + const retrievedState = await retrieveState(client, workspaceSlug, projectId, stateObj.id); console.log("Retrieved state: ", retrievedState); - const updatedState = await updateState( - client, - workspaceSlug, - projectId, - stateObj.id, - stateObj - ); + const updatedState = await updateState(client, workspaceSlug, projectId, stateObj.id, stateObj); console.log("Updated state: ", updatedState); const states = await listStates(client, workspaceSlug, projectId); @@ -36,11 +30,7 @@ export async function testStates() { console.log("State deleted: ", stateObj.id); } -async function createState( - client: PlaneClient, - workspaceSlug: string, - projectId: string -) { +async function createState(client: PlaneClient, workspaceSlug: string, projectId: string) { const state = await client.states.create(workspaceSlug, projectId, { name: "Test State " + new Date().getTime(), description: "Test State Description", @@ -50,12 +40,7 @@ async function createState( return state; } -async function retrieveState( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - stateId: string -) { +async function retrieveState(client: PlaneClient, workspaceSlug: string, projectId: string, stateId: string) { const state = await client.states.retrieve(workspaceSlug, projectId, stateId); return state; } @@ -67,32 +52,18 @@ async function updateState( stateId: string, state: State ) { - const updatedState = await client.states.update( - workspaceSlug, - projectId, - stateId, - { - description: "Updated Test State Description", - } - ); + const updatedState = await client.states.update(workspaceSlug, projectId, stateId, { + description: "Updated Test State Description", + }); return updatedState; } -async function listStates( - client: PlaneClient, - workspaceSlug: string, - projectId: string -) { +async function listStates(client: PlaneClient, workspaceSlug: string, projectId: string) { const states = await client.states.list(workspaceSlug, projectId); return states; } -async function deleteState( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - stateId: string -) { +async function deleteState(client: PlaneClient, workspaceSlug: string, projectId: string, stateId: string) { await client.states.delete(workspaceSlug, projectId, stateId); } diff --git a/tests/unit/test-utils.ts b/tests/unit/test-utils.ts index 870e628..7f4f04c 100644 --- a/tests/unit/test-utils.ts +++ b/tests/unit/test-utils.ts @@ -1,4 +1,4 @@ -import { PlaneClient } from "../src/client/plane-client"; +import { PlaneClient } from "../../src/client/plane-client"; /** * Creates a configured PlaneClient instance for testing @@ -8,7 +8,6 @@ export function createTestClient(): PlaneClient { return new PlaneClient({ apiKey: process.env.PLANE_API_KEY!, baseUrl: process.env.PLANE_BASE_URL!, - enableLogging: true, }); } diff --git a/tests/unit/work-item-types/properties-options.test.ts b/tests/unit/work-item-types/properties-options.test.ts index 20b5a24..b58b5df 100644 --- a/tests/unit/work-item-types/properties-options.test.ts +++ b/tests/unit/work-item-types/properties-options.test.ts @@ -1,10 +1,10 @@ -import { PlaneClient } from "../../src/client/plane-client"; -import { PropertyType } from "../../src/models/common"; +import { PlaneClient } from "../../../src/client/plane-client"; +import { PropertyType } from "../../../src/models/common"; import { WorkItemProperty, WorkItemPropertyOption, WorkItemPropertySettings, -} from "../../src/models/WorkItemProperty"; +} from "../../../src/models/WorkItemProperty"; import { config } from "../constants"; import { createTestClient } from "../test-utils"; @@ -15,10 +15,9 @@ export async function testWorkItemTypesPropertiesAndOptions() { const projectId = config.projectId; const workItemTypeId = config.workItemTypeId; - if (!workItemTypeId) { - throw new Error( - "workItemTypeId is required to test work item properties and options" - ); + if (!workspaceSlug || !projectId || !workItemTypeId) { + console.error("workspaceSlug, projectId and workItemTypeId are required"); + return; } // enable work item types if didn't already @@ -46,10 +45,7 @@ export async function testWorkItemTypesPropertiesAndOptions() { workItemTypeId, workItemTypeProperty.id ); - console.log( - "Retrieved work item type property: ", - retrievedWorkItemTypeProperty - ); + console.log("Retrieved work item type property: ", retrievedWorkItemTypeProperty); const updatedWorkItemTypeProperty = await updateWorkItemTypeProperty( client, @@ -60,21 +56,10 @@ export async function testWorkItemTypesPropertiesAndOptions() { ); console.log("Updated work item type property: ", updatedWorkItemTypeProperty); - const workItemTypeProperties = await listWorkItemTypeProperties( - client, - workspaceSlug, - projectId, - workItemTypeId - ); + const workItemTypeProperties = await listWorkItemTypeProperties(client, workspaceSlug, projectId, workItemTypeId); console.log("Listed work item type properties: ", workItemTypeProperties); - await deleteWorkItemTypeProperty( - client, - workspaceSlug, - projectId, - workItemTypeId, - workItemTypeProperty.id - ); + await deleteWorkItemTypeProperty(client, workspaceSlug, projectId, workItemTypeId, workItemTypeProperty.id); console.log("Work item type property deleted: ", workItemTypeProperty.id); // test the work item type property options @@ -88,15 +73,10 @@ export async function testWorkItemTypesPropertiesAndOptions() { workItemTypeId, "OPTION" ); - console.log( - "Created option work item type property: ", - optionWorkItemTypeProperty - ); + console.log("Created option work item type property: ", optionWorkItemTypeProperty); if (!optionWorkItemTypeProperty.id) { - throw new Error( - "optionWorkItemTypeProperty ID is required to test work item property options" - ); + throw new Error("optionWorkItemTypeProperty ID is required to test work item property options"); } const createdWorkItemPropertyOption = await createWorkItemPropertyOption( @@ -105,10 +85,7 @@ export async function testWorkItemTypesPropertiesAndOptions() { projectId, optionWorkItemTypeProperty.id ); - console.log( - "Created work item property option: ", - createdWorkItemPropertyOption - ); + console.log("Created work item property option: ", createdWorkItemPropertyOption); const retrievedWorkItemPropertyOption = await retrieveWorkItemPropertyOption( client, @@ -117,10 +94,7 @@ export async function testWorkItemTypesPropertiesAndOptions() { optionWorkItemTypeProperty.id, createdWorkItemPropertyOption.id ); - console.log( - "Retrieved work item property option: ", - retrievedWorkItemPropertyOption - ); + console.log("Retrieved work item property option: ", retrievedWorkItemPropertyOption); const updatedWorkItemPropertyOption = await updateWorkItemPropertyOption( client, @@ -129,10 +103,7 @@ export async function testWorkItemTypesPropertiesAndOptions() { optionWorkItemTypeProperty.id, createdWorkItemPropertyOption.id ); - console.log( - "Updated work item property option: ", - updatedWorkItemPropertyOption - ); + console.log("Updated work item property option: ", updatedWorkItemPropertyOption); await deleteWorkItemPropertyOption( client, @@ -141,22 +112,10 @@ export async function testWorkItemTypesPropertiesAndOptions() { optionWorkItemTypeProperty.id, createdWorkItemPropertyOption.id ); - console.log( - "Work item property option deleted: ", - createdWorkItemPropertyOption.id - ); + console.log("Work item property option deleted: ", createdWorkItemPropertyOption.id); - await deleteWorkItemTypeProperty( - client, - workspaceSlug, - projectId, - workItemTypeId, - optionWorkItemTypeProperty.id - ); - console.log( - "Option work item type property deleted: ", - optionWorkItemTypeProperty.id - ); + await deleteWorkItemTypeProperty(client, workspaceSlug, projectId, workItemTypeId, optionWorkItemTypeProperty.id); + console.log("Option work item type property deleted: ", optionWorkItemTypeProperty.id); } async function createWorkItemTypeProperty( @@ -167,18 +126,13 @@ async function createWorkItemTypeProperty( propertyType: PropertyType, settings?: WorkItemPropertySettings ): Promise { - const workItemTypeProperty = await client.workItemProperties.create( - workspaceSlug, - projectId, - workItemTypeId, - { - name: `Test WI Type Property ${new Date().getTime()}`, - display_name: `Test WI Type Property ${new Date().getTime()}`, - property_type: propertyType, - settings, - is_required: false, - } - ); + const workItemTypeProperty = await client.workItemProperties.create(workspaceSlug, projectId, workItemTypeId, { + name: `Test WI Type Property ${new Date().getTime()}`, + display_name: `Test WI Type Property ${new Date().getTime()}`, + property_type: propertyType, + settings, + is_required: false, + }); return workItemTypeProperty; } @@ -204,15 +158,10 @@ async function listWorkItemTypeProperties( projectId: string, workItemTypeId: string ): Promise { - const workItemTypeProperties = await client.workItemProperties.list( - workspaceSlug, - projectId, - workItemTypeId, - { - limit: 10, - offset: 0, - } - ); + const workItemTypeProperties = await client.workItemProperties.list(workspaceSlug, projectId, workItemTypeId, { + limit: 10, + offset: 0, + }); return workItemTypeProperties; } @@ -242,12 +191,7 @@ async function deleteWorkItemTypeProperty( workItemTypeId: string, workItemPropertyId: string ): Promise { - await client.workItemProperties.delete( - workspaceSlug, - projectId, - workItemTypeId, - workItemPropertyId - ); + await client.workItemProperties.delete(workspaceSlug, projectId, workItemTypeId, workItemPropertyId); } async function createWorkItemPropertyOption( @@ -256,15 +200,14 @@ async function createWorkItemPropertyOption( projectId: string, workItemPropertyId: string ): Promise { - const workItemTypePropertyOption = - await client.workItemProperties.options.create( - workspaceSlug, - projectId, - workItemPropertyId, - { - name: `Test Property Option ${new Date().getTime()}`, - } - ); + const workItemTypePropertyOption = await client.workItemProperties.options.create( + workspaceSlug, + projectId, + workItemPropertyId, + { + name: `Test Property Option ${new Date().getTime()}`, + } + ); return workItemTypePropertyOption; } @@ -275,13 +218,12 @@ async function retrieveWorkItemPropertyOption( workItemPropertyId: string, workItemPropertyOptionId: string ): Promise { - const workItemTypePropertyOption = - await client.workItemProperties.options.retrieve( - workspaceSlug, - projectId, - workItemPropertyId, - workItemPropertyOptionId - ); + const workItemTypePropertyOption = await client.workItemProperties.options.retrieve( + workspaceSlug, + projectId, + workItemPropertyId, + workItemPropertyOptionId + ); return workItemTypePropertyOption; } @@ -292,16 +234,15 @@ async function updateWorkItemPropertyOption( workItemPropertyId: string, workItemPropertyOptionId: string ): Promise { - const workItemTypePropertyOption = - await client.workItemProperties.options.update( - workspaceSlug, - projectId, - workItemPropertyId, - workItemPropertyOptionId, - { - name: `Updated Property Option ${new Date().getTime()}`, - } - ); + const workItemTypePropertyOption = await client.workItemProperties.options.update( + workspaceSlug, + projectId, + workItemPropertyId, + workItemPropertyOptionId, + { + name: `Updated Property Option ${new Date().getTime()}`, + } + ); return workItemTypePropertyOption; } diff --git a/tests/unit/work-item-types/properties-values.test.ts b/tests/unit/work-item-types/properties-values.test.ts index 2b552de..29e2045 100644 --- a/tests/unit/work-item-types/properties-values.test.ts +++ b/tests/unit/work-item-types/properties-values.test.ts @@ -1,5 +1,5 @@ -import { PlaneClient } from "../../src/client/plane-client"; -import { WorkItemPropertyValues } from "../../src/models/WorkItemProperty"; +import { PlaneClient } from "../../../src/client/plane-client"; +import { WorkItemPropertyValues } from "../../../src/models/WorkItemProperty"; import { config } from "../constants"; import { createTestClient } from "../test-utils"; @@ -16,10 +16,9 @@ export async function testWorkItemPropertiesValues() { is_issue_type_enabled: true, }); - if (!workItemId || !propertyId) { - throw new Error( - "workItemId and propertyId are required to test work item properties and values" - ); + if (!workspaceSlug || !projectId || !workItemId || !propertyId) { + console.error("workItemId and propertyId are required to test work item properties and values"); + return; } const workItemPropertyValue = await updateWorkItemPropertyValue( @@ -38,17 +37,9 @@ export async function testWorkItemPropertiesValues() { workItemId, propertyId ); - console.log( - "Retrieved work item property value: ", - retrievedWorkItemPropertyValue - ); + console.log("Retrieved work item property value: ", retrievedWorkItemPropertyValue); - const workItemPropertyValues = await listWorkItemPropertyValues( - client, - workspaceSlug, - projectId, - workItemId - ); + const workItemPropertyValues = await listWorkItemPropertyValues(client, workspaceSlug, projectId, workItemId); console.log("Listed work item property values: ", workItemPropertyValues); } @@ -93,15 +84,10 @@ async function listWorkItemPropertyValues( projectId: string, workItemId: string ): Promise { - const workItemPropertyValues = await client.workItemProperties.values.list( - workspaceSlug, - projectId, - workItemId, - { - limit: 10, - offset: 0, - } - ); + const workItemPropertyValues = await client.workItemProperties.values.list(workspaceSlug, projectId, workItemId, { + limit: 10, + offset: 0, + }); return workItemPropertyValues; } diff --git a/tests/unit/work-item-types/types.test.ts b/tests/unit/work-item-types/types.test.ts index 80f0567..cadb465 100644 --- a/tests/unit/work-item-types/types.test.ts +++ b/tests/unit/work-item-types/types.test.ts @@ -1,6 +1,6 @@ -import { PlaneClient } from "../../src/client/plane-client"; -import { PaginatedResponse } from "../../src/models/common"; -import { WorkItemType } from "../../src/models/WorkItemType"; +import { PlaneClient } from "../../../src/client/plane-client"; +import { PaginatedResponse } from "../../../src/models/common"; +import { WorkItemType } from "../../../src/models/WorkItemType"; import { config } from "../constants"; import { createTestClient } from "../test-utils"; @@ -10,39 +10,26 @@ export async function testWorkItemTypes() { const workspaceSlug = config.workspaceSlug; const projectId = config.projectId; + if (!workspaceSlug || !projectId) { + console.error("workspaceSlug and projectId are required"); + return; + } + // enable work item types if didn't already await client.projects.update(workspaceSlug, projectId, { is_issue_type_enabled: true, }); - const workItemType = await createWorkItemType( - client, - workspaceSlug, - projectId - ); + const workItemType = await createWorkItemType(client, workspaceSlug, projectId); console.log("Created work item type: ", workItemType); - const retrievedWorkItemType = await retrieveWorkItemType( - client, - workspaceSlug, - projectId, - workItemType.id - ); + const retrievedWorkItemType = await retrieveWorkItemType(client, workspaceSlug, projectId, workItemType.id); console.log("Retrieved work item type: ", retrievedWorkItemType); - const updatedWorkItemType = await updateWorkItemType( - client, - workspaceSlug, - projectId, - workItemType.id - ); + const updatedWorkItemType = await updateWorkItemType(client, workspaceSlug, projectId, workItemType.id); console.log("Updated work item type: ", updatedWorkItemType); - const workItemTypes = await listWorkItemTypes( - client, - workspaceSlug, - projectId - ); + const workItemTypes = await listWorkItemTypes(client, workspaceSlug, projectId); console.log("Listed work item types: ", workItemTypes); await deleteWorkItemType(client, workspaceSlug, projectId, workItemType.id); @@ -54,13 +41,9 @@ async function createWorkItemType( workspaceSlug: string, projectId: string ): Promise { - const workItemType = await client.workItemTypes.create( - workspaceSlug, - projectId, - { - name: `Test WI Type ${new Date().getTime()}`, - } - ); + const workItemType = await client.workItemTypes.create(workspaceSlug, projectId, { + name: `Test WI Type ${new Date().getTime()}`, + }); return workItemType; } @@ -70,11 +53,7 @@ async function retrieveWorkItemType( projectId: string, workItemTypeId: string ): Promise { - const workItemType = await client.workItemTypes.retrieve( - workspaceSlug, - projectId, - workItemTypeId - ); + const workItemType = await client.workItemTypes.retrieve(workspaceSlug, projectId, workItemTypeId); return workItemType; } @@ -83,14 +62,10 @@ async function listWorkItemTypes( workspaceSlug: string, projectId: string ): Promise> { - const workItemTypes = await client.workItemTypes.list( - workspaceSlug, - projectId, - { - limit: 10, - offset: 0, - } - ); + const workItemTypes = await client.workItemTypes.list(workspaceSlug, projectId, { + limit: 10, + offset: 0, + }); return workItemTypes; } @@ -100,14 +75,9 @@ async function updateWorkItemType( projectId: string, workItemTypeId: string ): Promise { - const updatedWorkItemType = await client.workItemTypes.update( - workspaceSlug, - projectId, - workItemTypeId, - { - name: `Updated Test WI Type ${new Date().getTime()}`, - } - ); + const updatedWorkItemType = await client.workItemTypes.update(workspaceSlug, projectId, workItemTypeId, { + name: `Updated Test WI Type ${new Date().getTime()}`, + }); return updatedWorkItemType; } diff --git a/tests/unit/work-items/activities.test.ts b/tests/unit/work-items/activities.test.ts index bf08a84..d701b7e 100644 --- a/tests/unit/work-items/activities.test.ts +++ b/tests/unit/work-items/activities.test.ts @@ -1,4 +1,4 @@ -import { PlaneClient } from "../../src/client/plane-client"; +import { PlaneClient } from "../../../src/client/plane-client"; import { config } from "../constants"; import { createTestClient } from "../test-utils"; @@ -9,35 +9,20 @@ export async function testActivities() { const projectId = config.projectId; const workItemId = config.workItemId; - const activityResponse = await listActivities( - client, - workspaceSlug, - projectId, - workItemId - ); + if (!workspaceSlug || !projectId || !workItemId) { + console.error("workspaceSlug, projectId and workItemId are required"); + return; + } + + const activityResponse = await listActivities(client, workspaceSlug, projectId, workItemId); console.log("activities list", activityResponse); - const activity = await retrieveActivity( - client, - workspaceSlug, - projectId, - workItemId, - activityResponse.results[0].id - ); + const activity = await retrieveActivity(client, workspaceSlug, projectId, workItemId, activityResponse.results[0].id); console.log("activity retrieve", activity); } -async function listActivities( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemId: string -) { - const activities = await client.workItems.activities.list( - workspaceSlug, - projectId, - workItemId - ); +async function listActivities(client: PlaneClient, workspaceSlug: string, projectId: string, workItemId: string) { + const activities = await client.workItems.activities.list(workspaceSlug, projectId, workItemId); return activities; } @@ -48,12 +33,7 @@ async function retrieveActivity( workItemId: string, activityId: string ) { - const activity = await client.workItems.activities.retrieve( - workspaceSlug, - projectId, - workItemId, - activityId - ); + const activity = await client.workItems.activities.retrieve(workspaceSlug, projectId, workItemId, activityId); return activity; } diff --git a/tests/unit/work-items/comments.test.ts b/tests/unit/work-items/comments.test.ts index f808247..c7ecc05 100644 --- a/tests/unit/work-items/comments.test.ts +++ b/tests/unit/work-items/comments.test.ts @@ -1,5 +1,5 @@ -import { PlaneClient } from "../../src/client/plane-client"; -import { WorkItemCommentUpdateRequest } from "../../src/models/Comment"; +import { PlaneClient } from "../../../src/client/plane-client"; +import { WorkItemCommentUpdateRequest } from "../../../src/models/Comment"; import { config } from "../constants"; import { createTestClient } from "../test-utils"; @@ -10,58 +10,31 @@ export async function testComments() { const projectId = config.projectId; const workItemId = config.workItemId; - const comment = await createComment( - client, - workspaceSlug, - projectId, - workItemId - ); + if (!workspaceSlug || !projectId || !workItemId) { + console.error("workspaceSlug, projectId and workItemId are required"); + return; + } + + const comment = await createComment(client, workspaceSlug, projectId, workItemId); console.log("Created comment: ", comment); - const retrievedComment = await retrieveComment( - client, - workspaceSlug, - projectId, - workItemId, - comment.id - ); + const retrievedComment = await retrieveComment(client, workspaceSlug, projectId, workItemId, comment.id); console.log("Retrieved comment: ", retrievedComment); - const updatedComment = await updateComment( - client, - workspaceSlug, - projectId, - workItemId, - comment.id - ); + const updatedComment = await updateComment(client, workspaceSlug, projectId, workItemId, comment.id); console.log("Updated comment: ", updatedComment); - const comments = await listComments( - client, - workspaceSlug, - projectId, - workItemId - ); + const comments = await listComments(client, workspaceSlug, projectId, workItemId); console.log("Listed comments: ", comments); await deleteComment(client, workspaceSlug, projectId, workItemId, comment.id); console.log("Deleted comment: ", comment.id); } -async function createComment( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemId: string -) { - const comment = await client.workItems.comments.create( - workspaceSlug, - projectId, - workItemId, - { - comment_html: "

Test Comment

", - } - ); +async function createComment(client: PlaneClient, workspaceSlug: string, projectId: string, workItemId: string) { + const comment = await client.workItems.comments.create(workspaceSlug, projectId, workItemId, { + comment_html: "

Test Comment

", + }); return comment; } @@ -72,12 +45,7 @@ async function retrieveComment( workItemId: string, commentId: string ) { - const comment = await client.workItems.comments.retrieve( - workspaceSlug, - projectId, - workItemId, - commentId - ); + const comment = await client.workItems.comments.retrieve(workspaceSlug, projectId, workItemId, commentId); return comment; } @@ -88,28 +56,13 @@ async function updateComment( workItemId: string, commentId: string ) { - return await client.workItems.comments.update( - workspaceSlug, - projectId, - workItemId, - commentId, - { - comment_html: "

Updated Test Comment

", - } - ); + return await client.workItems.comments.update(workspaceSlug, projectId, workItemId, commentId, { + comment_html: "

Updated Test Comment

", + }); } -async function listComments( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemId: string -) { - const comments = await client.workItems.comments.list( - workspaceSlug, - projectId, - workItemId - ); +async function listComments(client: PlaneClient, workspaceSlug: string, projectId: string, workItemId: string) { + const comments = await client.workItems.comments.list(workspaceSlug, projectId, workItemId); return comments; } @@ -120,12 +73,7 @@ async function deleteComment( workItemId: string, commentId: string ) { - await client.workItems.comments.delete( - workspaceSlug, - projectId, - workItemId, - commentId - ); + await client.workItems.comments.delete(workspaceSlug, projectId, workItemId, commentId); } if (require.main === module) { diff --git a/tests/unit/work-items/links.test.ts b/tests/unit/work-items/links.test.ts index ada1994..3257e84 100644 --- a/tests/unit/work-items/links.test.ts +++ b/tests/unit/work-items/links.test.ts @@ -1,5 +1,5 @@ -import { PlaneClient } from "../../src/client/plane-client"; -import { Link } from "../../src/models/Link"; +import { PlaneClient } from "../../../src/client/plane-client"; +import { Link } from "../../../src/models/Link"; import { config } from "../constants"; import { createTestClient } from "../test-utils"; @@ -10,25 +10,18 @@ export async function testLinks() { const projectId = config.projectId; const workItemId = config.workItemId; + if (!workspaceSlug || !projectId || !workItemId) { + console.error("workspaceSlug, projectId and workItemId are required"); + return; + } + const link = await createLink(client, workspaceSlug, projectId, workItemId); console.log("Created link: ", link); - const retrievedLink = await retrieveLink( - client, - workspaceSlug, - projectId, - workItemId, - link.id - ); + const retrievedLink = await retrieveLink(client, workspaceSlug, projectId, workItemId, link.id); console.log("Retrieved link: ", retrievedLink); - const updatedLink = await updateLink( - client, - workspaceSlug, - projectId, - workItemId, - link.id - ); + const updatedLink = await updateLink(client, workspaceSlug, projectId, workItemId, link.id); console.log("Updated link: ", updatedLink); const links = await listLinks(client, workspaceSlug, projectId, workItemId); @@ -38,21 +31,11 @@ export async function testLinks() { console.log("Deleted link: ", link.id); } -async function createLink( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemId: string -) { - const link = await client.workItems.links.create( - workspaceSlug, - projectId, - workItemId, - { - title: "Test Link", - url: "https://test.com", - } - ); +async function createLink(client: PlaneClient, workspaceSlug: string, projectId: string, workItemId: string) { + const link = await client.workItems.links.create(workspaceSlug, projectId, workItemId, { + title: "Test Link", + url: "https://test.com", + }); return link; } @@ -63,12 +46,7 @@ async function retrieveLink( workItemId: string, linkId: string ) { - const link = await client.workItems.links.retrieve( - workspaceSlug, - projectId, - workItemId, - linkId - ); + const link = await client.workItems.links.retrieve(workspaceSlug, projectId, workItemId, linkId); return link; } @@ -79,29 +57,14 @@ async function updateLink( workItemId: string, linkId: string ) { - return await client.workItems.links.update( - workspaceSlug, - projectId, - workItemId, - linkId, - { - title: "Updated Test Link", - url: "https://updated.com", - } - ); + return await client.workItems.links.update(workspaceSlug, projectId, workItemId, linkId, { + title: "Updated Test Link", + url: "https://updated.com", + }); } -async function listLinks( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemId: string -) { - const links = await client.workItems.links.list( - workspaceSlug, - projectId, - workItemId - ); +async function listLinks(client: PlaneClient, workspaceSlug: string, projectId: string, workItemId: string) { + const links = await client.workItems.links.list(workspaceSlug, projectId, workItemId); return links; } @@ -112,12 +75,7 @@ async function deleteLink( workItemId: string, linkId: string ) { - await client.workItems.links.delete( - workspaceSlug, - projectId, - workItemId, - linkId - ); + await client.workItems.links.delete(workspaceSlug, projectId, workItemId, linkId); } if (require.main === module) { diff --git a/tests/unit/work-items/relations.test.ts b/tests/unit/work-items/relations.test.ts index 4095341..15fafd4 100644 --- a/tests/unit/work-items/relations.test.ts +++ b/tests/unit/work-items/relations.test.ts @@ -1,8 +1,5 @@ -import { PlaneClient } from "../../src/client/plane-client"; -import { - WorkItemRelationCreateRequest, - WorkItemRelationRemoveRequest, -} from "../../src/models/WorkItemRelation"; +import { PlaneClient } from "../../../src/client/plane-client"; +import { WorkItemRelationCreateRequest, WorkItemRelationRemoveRequest } from "../../../src/models/WorkItemRelation"; import { config } from "../constants"; import { createTestClient } from "../test-utils"; @@ -12,30 +9,22 @@ export async function testRelations() { const workspaceSlug = config.workspaceSlug; const projectId = config.projectId; const workItemId = config.workItemId; + const workItemId2 = config.workItemId2; - const workItem2 = await client.workItems.retrieveByIdentifier( - workspaceSlug, - config.workItemId2 - ); + if (!workspaceSlug || !projectId || !workItemId || !workItemId2) { + console.error("workspaceSlug, projectId, workItemId and workItemId2 are required"); + return; + } - const relationData = await createRelation( - client, - workspaceSlug, - projectId, - workItemId, - { - relation_type: "blocking", - issues: [workItem2.id], - } - ); + const workItem2 = await client.workItems.retrieveByIdentifier(workspaceSlug, workItemId2); + + const relationData = await createRelation(client, workspaceSlug, projectId, workItemId, { + relation_type: "blocking", + issues: [workItem2.id], + }); console.log("Created relation: ", relationData); - const relations = await listRelations( - client, - workspaceSlug, - projectId, - workItemId - ); + const relations = await listRelations(client, workspaceSlug, projectId, workItemId); console.log("Listed relations: ", relations); await deleteRelation(client, workspaceSlug, projectId, workItemId, { @@ -51,20 +40,10 @@ async function createRelation( workItemId: string, relationData: WorkItemRelationCreateRequest ) { - return client.workItems.relations.create( - workspaceSlug, - projectId, - workItemId, - relationData - ); + return client.workItems.relations.create(workspaceSlug, projectId, workItemId, relationData); } -async function listRelations( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemId: string -) { +async function listRelations(client: PlaneClient, workspaceSlug: string, projectId: string, workItemId: string) { return client.workItems.relations.list(workspaceSlug, projectId, workItemId); } @@ -75,12 +54,7 @@ async function deleteRelation( workItemId: string, relationData: WorkItemRelationRemoveRequest ) { - return client.workItems.relations.delete( - workspaceSlug, - projectId, - workItemId, - relationData - ); + return client.workItems.relations.delete(workspaceSlug, projectId, workItemId, relationData); } if (require.main === module) { diff --git a/tests/unit/work-items/work-items.test.ts b/tests/unit/work-items/work-items.test.ts index de6bcf1..ac0d5a4 100644 --- a/tests/unit/work-items/work-items.test.ts +++ b/tests/unit/work-items/work-items.test.ts @@ -1,4 +1,4 @@ -import { PlaneClient } from "../../src/client/plane-client"; +import { PlaneClient } from "../../../src/client/plane-client"; import { config } from "../constants"; import { createTestClient } from "../test-utils"; @@ -8,25 +8,20 @@ export async function testWorkItems() { const workspaceSlug = config.workspaceSlug; const projectId = config.projectId; + if (!workspaceSlug || !projectId) { + console.error("workspaceSlug and projectId are required"); + return; + } + const workItem = await createWorkItem(client, workspaceSlug, projectId); console.log("Created work item: ", workItem); await new Promise((resolve) => setTimeout(resolve, 1000)); - const retrievedWorkItem = await retrieveWorkItem( - client, - workspaceSlug, - projectId, - workItem.id - ); + const retrievedWorkItem = await retrieveWorkItem(client, workspaceSlug, projectId, workItem.id); console.log("Retrieved work item: ", retrievedWorkItem); await new Promise((resolve) => setTimeout(resolve, 1000)); - const updatedWorkItem = await updateWorkItem( - client, - workspaceSlug, - projectId, - workItem.id - ); + const updatedWorkItem = await updateWorkItem(client, workspaceSlug, projectId, workItem.id); console.log("Updated work item: ", updatedWorkItem); await new Promise((resolve) => setTimeout(resolve, 1000)); @@ -43,12 +38,7 @@ export async function testWorkItems() { console.log("Retrieved work item by identifier: ", workItemByIdentifier); await new Promise((resolve) => setTimeout(resolve, 1000)); - const searchedWorkItems = await searchWorkItems( - client, - workspaceSlug, - projectId, - workItemByIdentifier.name - ); + const searchedWorkItems = await searchWorkItems(client, workspaceSlug, projectId, workItemByIdentifier.name); console.log("Searched work items: ", searchedWorkItems); await new Promise((resolve) => setTimeout(resolve, 1000)); @@ -57,11 +47,7 @@ export async function testWorkItems() { console.log("Work item deleted: ", workItem.id); } -async function createWorkItem( - client: PlaneClient, - workspaceSlug: string, - projectId: string -) { +async function createWorkItem(client: PlaneClient, workspaceSlug: string, projectId: string) { const workItem = await client.workItems.create(workspaceSlug, projectId, { name: "Test Work Item", description_html: "

A work item created via the Plane SDK

", @@ -69,62 +55,34 @@ async function createWorkItem( return workItem; } -async function retrieveWorkItem( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemId: string -) { - const workItem = await client.workItems.retrieve( - workspaceSlug, - projectId, - workItemId - ); +async function retrieveWorkItem(client: PlaneClient, workspaceSlug: string, projectId: string, workItemId: string) { + const workItem = await client.workItems.retrieve(workspaceSlug, projectId, workItemId); return workItem; } -async function updateWorkItem( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemId: string -) { +async function updateWorkItem(client: PlaneClient, workspaceSlug: string, projectId: string, workItemId: string) { const states = await client.states.list(workspaceSlug, projectId); const labels = await client.labels.list(workspaceSlug, projectId); const label = labels.results[0]; const state = states.results[0]; - const updatedWorkItem = await client.workItems.update( - workspaceSlug, - projectId, - workItemId, - { - name: "Updated Test Work Item", - description_html: "

Updated Test Work Item Description

", - state: state ? state.id : undefined, - assignees: [config.userId], - labels: label ? [label.id] : undefined, - } - ); + const updatedWorkItem = await client.workItems.update(workspaceSlug, projectId, workItemId, { + name: "Updated Test Work Item", + description_html: "

Updated Test Work Item Description

", + state: state ? state.id : undefined, + assignees: [config.userId], + labels: label ? [label.id] : undefined, + }); return updatedWorkItem; } -async function listWorkItems( - client: PlaneClient, - workspaceSlug: string, - projectId: string -) { +async function listWorkItems(client: PlaneClient, workspaceSlug: string, projectId: string) { const workItems = await client.workItems.list(workspaceSlug, projectId); return workItems; } -async function deleteWorkItem( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemId: string -) { +async function deleteWorkItem(client: PlaneClient, workspaceSlug: string, projectId: string, workItemId: string) { await client.workItems.delete(workspaceSlug, projectId, workItemId); } @@ -135,25 +93,14 @@ async function retrieveWorkItemByIdentifier( identifier: number ) { const project = await client.projects.retrieve(workspaceSlug, projectId); - const workItem = await client.workItems.retrieveByIdentifier( - workspaceSlug, - `${project.identifier}-${identifier}`, - ["project"] - ); + const workItem = await client.workItems.retrieveByIdentifier(workspaceSlug, `${project.identifier}-${identifier}`, [ + "project", + ]); return workItem; } -async function searchWorkItems( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - query: string -) { - const workItems = await client.workItems.search( - workspaceSlug, - projectId, - query - ); +async function searchWorkItems(client: PlaneClient, workspaceSlug: string, projectId: string, query: string) { + const workItems = await client.workItems.search(workspaceSlug, projectId, query); return workItems; } diff --git a/tests/unit/work-items/work-logs.test.ts b/tests/unit/work-items/work-logs.test.ts index b5860f6..b01af61 100644 --- a/tests/unit/work-items/work-logs.test.ts +++ b/tests/unit/work-items/work-logs.test.ts @@ -1,4 +1,4 @@ -import { PlaneClient } from "../../src/client/plane-client"; +import { PlaneClient } from "../../../src/client/plane-client"; import { config } from "../constants"; import { createTestClient } from "../test-utils"; @@ -9,6 +9,11 @@ export async function testWorkLogs() { const projectId = config.projectId; const workItemId = config.workItemId; + if (!workspaceSlug || !projectId || !workItemId) { + console.error("workspaceSlug, projectId and workItemId are required"); + return; + } + await client.projects.update(workspaceSlug, projectId, { is_time_tracking_enabled: true, }); @@ -17,58 +22,27 @@ export async function testWorkLogs() { console.log("Time tracking enabled: ", project.is_time_tracking_enabled); - const workLog = await createWorkLog( - client, - workspaceSlug, - projectId, - workItemId - ); + const workLog = await createWorkLog(client, workspaceSlug, projectId, workItemId); console.log("Created work log: ", workLog); - const workLogs = await listWorkLogs( - client, - workspaceSlug, - projectId, - workItemId - ); + const workLogs = await listWorkLogs(client, workspaceSlug, projectId, workItemId); console.log("Listed work logs: ", workLogs); - const updatedWorkLog = await updateWorkLog( - client, - workspaceSlug, - projectId, - workItemId, - workLog.id - ); + const updatedWorkLog = await updateWorkLog(client, workspaceSlug, projectId, workItemId, workLog.id); console.log("Updated work log: ", updatedWorkLog); await deleteWorkLog(client, workspaceSlug, projectId, workItemId, workLog.id); console.log("Deleted work log: ", workLog.id); } -async function createWorkLog( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemId: string -) { - return client.workItems.workLogs.create( - workspaceSlug, - projectId, - workItemId, - { - duration: 30, - description: "Test work log", - } - ); +async function createWorkLog(client: PlaneClient, workspaceSlug: string, projectId: string, workItemId: string) { + return client.workItems.workLogs.create(workspaceSlug, projectId, workItemId, { + duration: 30, + description: "Test work log", + }); } -async function listWorkLogs( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemId: string -) { +async function listWorkLogs(client: PlaneClient, workspaceSlug: string, projectId: string, workItemId: string) { return client.workItems.workLogs.list(workspaceSlug, projectId, workItemId); } @@ -79,15 +53,9 @@ async function updateWorkLog( workItemId: string, workLogId: string ) { - return client.workItems.workLogs.update( - workspaceSlug, - projectId, - workItemId, - workLogId, - { - description: "Updated test work log", - } - ); + return client.workItems.workLogs.update(workspaceSlug, projectId, workItemId, workLogId, { + description: "Updated test work log", + }); } async function deleteWorkLog( @@ -97,12 +65,7 @@ async function deleteWorkLog( workItemId: string, workLogId: string ) { - return client.workItems.workLogs.delete( - workspaceSlug, - projectId, - workItemId, - workLogId - ); + return client.workItems.workLogs.delete(workspaceSlug, projectId, workItemId, workLogId); } if (require.main === module) { From c6d57a6304d97cc6ff121528587b8a8505f00b82 Mon Sep 17 00:00:00 2001 From: Surya Prashanth Date: Tue, 28 Oct 2025 19:34:44 +0530 Subject: [PATCH 3/6] create helpers folder for test helpers --- tests/unit/customers/customers.test.ts | 2 +- .../unit/customers/properties-options.test.ts | 2 +- tests/unit/customers/requests.test.ts | 2 +- tests/unit/customers/work-items.test.ts | 2 +- tests/unit/cycle.test.ts | 2 +- tests/unit/epic.test.ts | 2 +- tests/unit/intake.test.ts | 2 +- tests/unit/label.test.ts | 2 +- tests/unit/module.test.ts | 2 +- tests/unit/page.test.ts | 2 +- tests/unit/project.test.ts | 2 +- tests/unit/state.test.ts | 2 +- tests/unit/test-utils.ts | 21 ------------------- .../properties-options.test.ts | 2 +- .../work-item-types/properties-values.test.ts | 2 +- tests/unit/work-item-types/types.test.ts | 2 +- tests/unit/work-items/activities.test.ts | 2 +- tests/unit/work-items/comments.test.ts | 2 +- tests/unit/work-items/links.test.ts | 2 +- tests/unit/work-items/relations.test.ts | 2 +- tests/unit/work-items/work-items.test.ts | 2 +- tests/unit/work-items/work-logs.test.ts | 2 +- 22 files changed, 21 insertions(+), 42 deletions(-) delete mode 100644 tests/unit/test-utils.ts diff --git a/tests/unit/customers/customers.test.ts b/tests/unit/customers/customers.test.ts index 1936e64..cd7274d 100644 --- a/tests/unit/customers/customers.test.ts +++ b/tests/unit/customers/customers.test.ts @@ -1,6 +1,6 @@ import { PlaneClient } from "../../../src/client/plane-client"; import { config } from "../constants"; -import { createTestClient } from "../test-utils"; +import { createTestClient } from "../../helpers/test-utils"; export async function testCustomers() { const client = createTestClient(); diff --git a/tests/unit/customers/properties-options.test.ts b/tests/unit/customers/properties-options.test.ts index cb8a2b4..6b7d6dd 100644 --- a/tests/unit/customers/properties-options.test.ts +++ b/tests/unit/customers/properties-options.test.ts @@ -1,6 +1,6 @@ import { PlaneClient } from "../../../src/client/plane-client"; import { config } from "../constants"; -import { createTestClient } from "../test-utils"; +import { createTestClient } from "../../helpers/test-utils"; export async function testCustomersPropertiesOptionsAndValues() { const client = createTestClient(); diff --git a/tests/unit/customers/requests.test.ts b/tests/unit/customers/requests.test.ts index fc1bf6c..290d84f 100644 --- a/tests/unit/customers/requests.test.ts +++ b/tests/unit/customers/requests.test.ts @@ -1,6 +1,6 @@ import { PlaneClient } from "../../../src/client/plane-client"; import { config } from "../constants"; -import { createTestClient } from "../test-utils"; +import { createTestClient } from "../../helpers/test-utils"; export async function testCustomersRequests() { const client = createTestClient(); diff --git a/tests/unit/customers/work-items.test.ts b/tests/unit/customers/work-items.test.ts index 585468d..5bb89d6 100644 --- a/tests/unit/customers/work-items.test.ts +++ b/tests/unit/customers/work-items.test.ts @@ -1,6 +1,6 @@ import { PlaneClient } from "../../../src/client/plane-client"; import { config } from "../constants"; -import { createTestClient } from "../test-utils"; +import { createTestClient } from "../../helpers/test-utils"; export async function testCustomersWorkItems() { const client = createTestClient(); diff --git a/tests/unit/cycle.test.ts b/tests/unit/cycle.test.ts index a54c8c5..ca407d7 100644 --- a/tests/unit/cycle.test.ts +++ b/tests/unit/cycle.test.ts @@ -1,7 +1,7 @@ import { PlaneClient } from "../../src/client/plane-client"; import { UpdateCycleRequest } from "../../src/models/Cycle"; import { config } from "./constants"; -import { createTestClient } from "./test-utils"; +import { createTestClient } from "../helpers/test-utils"; export async function testCycles() { const client = createTestClient(); diff --git a/tests/unit/epic.test.ts b/tests/unit/epic.test.ts index 0d347a5..58979c2 100644 --- a/tests/unit/epic.test.ts +++ b/tests/unit/epic.test.ts @@ -1,6 +1,6 @@ import { PlaneClient } from "../../src/client/plane-client"; import { config } from "./constants"; -import { createTestClient } from "./test-utils"; +import { createTestClient } from "../helpers/test-utils"; export async function testEpics() { const client = createTestClient(); diff --git a/tests/unit/intake.test.ts b/tests/unit/intake.test.ts index 2ee2ce8..db04bdf 100644 --- a/tests/unit/intake.test.ts +++ b/tests/unit/intake.test.ts @@ -2,7 +2,7 @@ import { PlaneClient } from "../../src/client/plane-client"; import { PaginatedResponse } from "../../src/models/common"; import { IntakeWorkItem } from "../../src/models/Intake"; import { config } from "./constants"; -import { createTestClient } from "./test-utils"; +import { createTestClient } from "../helpers/test-utils"; export async function testIntake() { const client = createTestClient(); diff --git a/tests/unit/label.test.ts b/tests/unit/label.test.ts index bc6dc22..4e7a9d1 100644 --- a/tests/unit/label.test.ts +++ b/tests/unit/label.test.ts @@ -1,7 +1,7 @@ import { PlaneClient } from "../../src/client/plane-client"; import { Label } from "../../src/models/Label"; import { config } from "./constants"; -import { createTestClient } from "./test-utils"; +import { createTestClient } from "../helpers/test-utils"; export async function testLabels() { const client = createTestClient(); diff --git a/tests/unit/module.test.ts b/tests/unit/module.test.ts index 7049f65..ab31f1a 100644 --- a/tests/unit/module.test.ts +++ b/tests/unit/module.test.ts @@ -1,7 +1,7 @@ import { PlaneClient } from "../../src/client/plane-client"; import { UpdateModuleRequest } from "../../src/models/Module"; import { config } from "./constants"; -import { createTestClient } from "./test-utils"; +import { createTestClient } from "../helpers/test-utils"; export async function testModules() { const client = createTestClient(); diff --git a/tests/unit/page.test.ts b/tests/unit/page.test.ts index 762c86a..f3a1220 100644 --- a/tests/unit/page.test.ts +++ b/tests/unit/page.test.ts @@ -1,7 +1,7 @@ import fs from "fs"; import { PlaneClient } from "../../src/client/plane-client"; import { config } from "./constants"; -import { createTestClient } from "./test-utils"; +import { createTestClient } from "../helpers/test-utils"; export async function testPage() { const client = createTestClient(); diff --git a/tests/unit/project.test.ts b/tests/unit/project.test.ts index dbc0af4..02bd3ee 100644 --- a/tests/unit/project.test.ts +++ b/tests/unit/project.test.ts @@ -1,7 +1,7 @@ import { PlaneClient } from "../../src/client/plane-client"; import { UpdateProject } from "../../src/models/Project"; import { config } from "./constants"; -import { createTestClient } from "./test-utils"; +import { createTestClient } from "../helpers/test-utils"; export async function testProjects() { const client = createTestClient(); diff --git a/tests/unit/state.test.ts b/tests/unit/state.test.ts index 8b5f83d..73c6be4 100644 --- a/tests/unit/state.test.ts +++ b/tests/unit/state.test.ts @@ -1,7 +1,7 @@ import { PlaneClient } from "../../src/client/plane-client"; import { State } from "../../src/models/State"; import { config } from "./constants"; -import { createTestClient } from "./test-utils"; +import { createTestClient } from "../helpers/test-utils"; export async function testStates() { const client = createTestClient(); diff --git a/tests/unit/test-utils.ts b/tests/unit/test-utils.ts deleted file mode 100644 index 7f4f04c..0000000 --- a/tests/unit/test-utils.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { PlaneClient } from "../../src/client/plane-client"; - -/** - * Creates a configured PlaneClient instance for testing - * @returns PlaneClient instance with test configuration - */ -export function createTestClient(): PlaneClient { - return new PlaneClient({ - apiKey: process.env.PLANE_API_KEY!, - baseUrl: process.env.PLANE_BASE_URL!, - }); -} - -/** - * Waits for a given number of seconds - * @param seconds - The number of seconds to wait - * @returns A promise that resolves after the given number of seconds - */ -export function wait(seconds = 60): Promise { - return new Promise((resolve) => setTimeout(resolve, seconds * 1000)); -} diff --git a/tests/unit/work-item-types/properties-options.test.ts b/tests/unit/work-item-types/properties-options.test.ts index b58b5df..c28c13c 100644 --- a/tests/unit/work-item-types/properties-options.test.ts +++ b/tests/unit/work-item-types/properties-options.test.ts @@ -6,7 +6,7 @@ import { WorkItemPropertySettings, } from "../../../src/models/WorkItemProperty"; import { config } from "../constants"; -import { createTestClient } from "../test-utils"; +import { createTestClient } from "../../helpers/test-utils"; export async function testWorkItemTypesPropertiesAndOptions() { const client = createTestClient(); diff --git a/tests/unit/work-item-types/properties-values.test.ts b/tests/unit/work-item-types/properties-values.test.ts index 29e2045..4390eea 100644 --- a/tests/unit/work-item-types/properties-values.test.ts +++ b/tests/unit/work-item-types/properties-values.test.ts @@ -1,7 +1,7 @@ import { PlaneClient } from "../../../src/client/plane-client"; import { WorkItemPropertyValues } from "../../../src/models/WorkItemProperty"; import { config } from "../constants"; -import { createTestClient } from "../test-utils"; +import { createTestClient } from "../../helpers/test-utils"; export async function testWorkItemPropertiesValues() { const client = createTestClient(); diff --git a/tests/unit/work-item-types/types.test.ts b/tests/unit/work-item-types/types.test.ts index cadb465..dd10ece 100644 --- a/tests/unit/work-item-types/types.test.ts +++ b/tests/unit/work-item-types/types.test.ts @@ -2,7 +2,7 @@ import { PlaneClient } from "../../../src/client/plane-client"; import { PaginatedResponse } from "../../../src/models/common"; import { WorkItemType } from "../../../src/models/WorkItemType"; import { config } from "../constants"; -import { createTestClient } from "../test-utils"; +import { createTestClient } from "../../helpers/test-utils"; export async function testWorkItemTypes() { const client = createTestClient(); diff --git a/tests/unit/work-items/activities.test.ts b/tests/unit/work-items/activities.test.ts index d701b7e..28fa207 100644 --- a/tests/unit/work-items/activities.test.ts +++ b/tests/unit/work-items/activities.test.ts @@ -1,6 +1,6 @@ import { PlaneClient } from "../../../src/client/plane-client"; import { config } from "../constants"; -import { createTestClient } from "../test-utils"; +import { createTestClient } from "../../helpers/test-utils"; export async function testActivities() { const client = createTestClient(); diff --git a/tests/unit/work-items/comments.test.ts b/tests/unit/work-items/comments.test.ts index c7ecc05..ebf5d85 100644 --- a/tests/unit/work-items/comments.test.ts +++ b/tests/unit/work-items/comments.test.ts @@ -1,7 +1,7 @@ import { PlaneClient } from "../../../src/client/plane-client"; import { WorkItemCommentUpdateRequest } from "../../../src/models/Comment"; import { config } from "../constants"; -import { createTestClient } from "../test-utils"; +import { createTestClient } from "../../helpers/test-utils"; export async function testComments() { const client = createTestClient(); diff --git a/tests/unit/work-items/links.test.ts b/tests/unit/work-items/links.test.ts index 3257e84..08fac7f 100644 --- a/tests/unit/work-items/links.test.ts +++ b/tests/unit/work-items/links.test.ts @@ -1,7 +1,7 @@ import { PlaneClient } from "../../../src/client/plane-client"; import { Link } from "../../../src/models/Link"; import { config } from "../constants"; -import { createTestClient } from "../test-utils"; +import { createTestClient } from "../../helpers/test-utils"; export async function testLinks() { const client = createTestClient(); diff --git a/tests/unit/work-items/relations.test.ts b/tests/unit/work-items/relations.test.ts index 15fafd4..a749276 100644 --- a/tests/unit/work-items/relations.test.ts +++ b/tests/unit/work-items/relations.test.ts @@ -1,7 +1,7 @@ import { PlaneClient } from "../../../src/client/plane-client"; import { WorkItemRelationCreateRequest, WorkItemRelationRemoveRequest } from "../../../src/models/WorkItemRelation"; import { config } from "../constants"; -import { createTestClient } from "../test-utils"; +import { createTestClient } from "../../helpers/test-utils"; export async function testRelations() { const client = createTestClient(); diff --git a/tests/unit/work-items/work-items.test.ts b/tests/unit/work-items/work-items.test.ts index ac0d5a4..8e45696 100644 --- a/tests/unit/work-items/work-items.test.ts +++ b/tests/unit/work-items/work-items.test.ts @@ -1,6 +1,6 @@ import { PlaneClient } from "../../../src/client/plane-client"; import { config } from "../constants"; -import { createTestClient } from "../test-utils"; +import { createTestClient } from "../../helpers/test-utils"; export async function testWorkItems() { const client = createTestClient(); diff --git a/tests/unit/work-items/work-logs.test.ts b/tests/unit/work-items/work-logs.test.ts index b01af61..9bcbc4b 100644 --- a/tests/unit/work-items/work-logs.test.ts +++ b/tests/unit/work-items/work-logs.test.ts @@ -1,6 +1,6 @@ import { PlaneClient } from "../../../src/client/plane-client"; import { config } from "../constants"; -import { createTestClient } from "../test-utils"; +import { createTestClient } from "../../helpers/test-utils"; export async function testWorkLogs() { const client = createTestClient(); From 39d2f603198f07ace9cf124b819c54b0862c2542 Mon Sep 17 00:00:00 2001 From: Surya Prashanth Date: Tue, 28 Oct 2025 20:39:00 +0530 Subject: [PATCH 4/6] feat: add e2e test to verify project use case --- package.json | 1 + src/api/BaseResource.ts | 2 + src/api/Modules.ts | 2 +- src/models/Cycle.ts | 5 + src/models/WorkItem.ts | 14 +++ src/models/index.ts | 2 + tests/e2e/config.ts | 3 + tests/e2e/project.spec.ts | 179 ++++++++++++++++++++++++++++++++++++ tests/helpers/test-utils.ts | 31 +++++++ tests/unit/cycle.test.ts | 1 + tests/unit/module.test.ts | 2 +- tests/unit/setup.ts | 43 --------- 12 files changed, 240 insertions(+), 45 deletions(-) create mode 100644 tests/e2e/config.ts create mode 100644 tests/e2e/project.spec.ts create mode 100644 tests/helpers/test-utils.ts delete mode 100644 tests/unit/setup.ts diff --git a/package.json b/package.json index e0112f0..dfd87e7 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "scripts": { "build": "tsc", "dev": "tsc --watch", + "test": "jest", "test:unit": "ts-node tests/unit/run-all.test.ts", "lint": "eslint src/**/*.ts", "format": "prettier --write src/**/*.ts", diff --git a/src/api/BaseResource.ts b/src/api/BaseResource.ts index bf5524f..f1e24bf 100644 --- a/src/api/BaseResource.ts +++ b/src/api/BaseResource.ts @@ -153,6 +153,8 @@ export abstract class BaseResource { * Centralized error handling */ protected handleError(error: any): never { + console.error("❌ [ERROR]", error); + if (error instanceof HttpError) { throw error; } diff --git a/src/api/Modules.ts b/src/api/Modules.ts index e43a41b..4b5c1b6 100644 --- a/src/api/Modules.ts +++ b/src/api/Modules.ts @@ -75,7 +75,7 @@ export class Modules extends BaseResource { /** * Add work items to module */ - async addWorkItemToModule( + async addWorkItemsToModule( workspaceSlug: string, projectId: string, moduleId: string, diff --git a/src/models/Cycle.ts b/src/models/Cycle.ts index dd7a31c..bc58bc8 100644 --- a/src/models/Cycle.ts +++ b/src/models/Cycle.ts @@ -21,7 +21,9 @@ export interface CycleWorkItem { export interface Cycle extends BaseModel { name: string; description?: string; + // YYYY-MM-DD format start_date?: string; + // YYYY-MM-DD format end_date?: string; view_props?: any; sort_order?: number; @@ -38,12 +40,15 @@ export interface Cycle extends BaseModel { export interface CreateCycleRequest { name: string; description?: string; + // YYYY-MM-DD format start_date?: string; + // YYYY-MM-DD format end_date?: string; owned_by: string; external_source?: string; external_id?: string; timezone?: TimezoneEnum; + project_id: string; } export interface UpdateCycleRequest { diff --git a/src/models/WorkItem.ts b/src/models/WorkItem.ts index b0901ea..a82219d 100644 --- a/src/models/WorkItem.ts +++ b/src/models/WorkItem.ts @@ -57,6 +57,13 @@ export interface CreateWorkItem { state?: string; assignees?: string[]; labels?: string[]; + parent?: string; + estimate_point?: string; + type?: string; + module?: string; + target_date?: string; + start_date?: string; + priority?: PriorityEnum; } export interface UpdateWorkItem { @@ -65,6 +72,13 @@ export interface UpdateWorkItem { state?: string; assignees?: string[]; labels?: string[]; + parent?: string; + estimate_point?: string; + type?: string; + module?: string; + target_date?: string; + start_date?: string; + priority?: PriorityEnum; } export interface ListWorkItemsParams { diff --git a/src/models/index.ts b/src/models/index.ts index 70a7609..bbac8b4 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -6,3 +6,5 @@ export * from "./Attachment"; export * from "./Link"; export * from "./Customer"; export * from "./Page"; +export * from "./Cycle"; +export * from "./Module"; diff --git a/tests/e2e/config.ts b/tests/e2e/config.ts new file mode 100644 index 0000000..1a5a7cb --- /dev/null +++ b/tests/e2e/config.ts @@ -0,0 +1,3 @@ +export const e2eConfig = { + workspaceSlug: process.env.TEST_WORKSPACE_SLUG!, +}; diff --git a/tests/e2e/project.spec.ts b/tests/e2e/project.spec.ts new file mode 100644 index 0000000..b4c5119 --- /dev/null +++ b/tests/e2e/project.spec.ts @@ -0,0 +1,179 @@ +import { createTestClient, randomizeName, wait } from "../helpers/test-utils"; +import { e2eConfig } from "./config"; +import { Project, Cycle, Module, WorkItem } from "../../src/models"; + +describe("End to End Project Test", () => { + // Shared state across tests + let client: ReturnType; + let userId: string; + let project: Project; + let cycle: Cycle; + let module: Module; + let workItem1: WorkItem; + let workItem2: WorkItem; + let workItem3: WorkItem; + + beforeAll(async () => { + // Initialize client and create prerequisites for all tests + client = createTestClient(); + + // Get current user - needed for assignees and cycle owners + const me = await client.users.me(); + userId = me.id!; + + // Create project - all tests depend on this + const projectName = randomizeName(); + project = await client.projects.create(e2eConfig.workspaceSlug, { + name: projectName, + id: projectName.slice(0, 5).toUpperCase(), + }); + }); + + it("should create and list cycles", async () => { + const cycleName = randomizeName("Test Cycle"); + cycle = await client.cycles.create(e2eConfig.workspaceSlug, project.id, { + name: cycleName, + description: "Test Cycle Description", + // YYYY-MM-DD format + start_date: new Date().toISOString().split("T")[0], + // YYYY-MM-DD format + end_date: new Date(new Date().setDate(new Date().getDate() + 14)).toISOString().split("T")[0], + owned_by: userId, + project_id: project.id, + }); + + expect(cycle).toBeDefined(); + expect(cycle.id).toBeDefined(); + expect(cycle.name).toBe(cycleName); + + const cycles = await client.cycles.list(e2eConfig.workspaceSlug, project.id); + expect(cycles.results.length).toBeGreaterThan(0); + expect(cycles.results.find((c) => c.name === cycle.name)).toBeDefined(); + }); + + it("should create and list modules", async () => { + const moduleName = randomizeName("Test Module"); + module = await client.modules.create(e2eConfig.workspaceSlug, project.id, { + name: moduleName, + description: "Test Module Description", + }); + + expect(module).toBeDefined(); + expect(module.id).toBeDefined(); + expect(module.name).toBe(moduleName); + + const modules = await client.modules.list(e2eConfig.workspaceSlug, project.id); + expect(modules.results.length).toBeGreaterThan(0); + expect(modules.results.find((m) => m.name === module.name)).toBeDefined(); + }); + + it("should create work items with assignees", async () => { + workItem1 = await client.workItems.create(e2eConfig.workspaceSlug, project.id, { + name: randomizeName("Test Work Item 1"), + description_html: "

Test Work Item 1 Description

", + assignees: [userId], + }); + + expect(workItem1).toBeDefined(); + expect(workItem1.id).toBeDefined(); + expect(workItem1.assignees).toBeDefined(); + + workItem2 = await client.workItems.create(e2eConfig.workspaceSlug, project.id, { + name: randomizeName("Test Work Item 2"), + description_html: "

Test Work Item 2 Description

", + assignees: [userId], + }); + + expect(workItem2).toBeDefined(); + expect(workItem2.id).toBeDefined(); + expect(workItem2.assignees).toHaveLength(1); + + const workItems = await client.workItems.list(e2eConfig.workspaceSlug, project.id); + expect(workItems.results.length).toBeGreaterThan(0); + }); + + it("should create work item relations", async () => { + await client.workItems.relations.create(e2eConfig.workspaceSlug, project.id, workItem1.id, { + relation_type: "relates_to", + issues: [workItem2.id], + }); + + const relations = await client.workItems.relations.list(e2eConfig.workspaceSlug, project.id, workItem1.id); + expect(relations.relates_to).toBeDefined(); + expect(relations.relates_to[0]).toBe(workItem2.id); + }); + + it("should create work item with parent relationship", async () => { + workItem3 = await client.workItems.create(e2eConfig.workspaceSlug, project.id, { + name: randomizeName("Test Work Item 3"), + description_html: "

Test Work Item 3 Description

", + assignees: [userId], + parent: workItem1.id, + }); + + expect(workItem3).toBeDefined(); + expect(workItem3.id).toBeDefined(); + + const workItem3Details = await client.workItems.retrieve(e2eConfig.workspaceSlug, project.id, workItem3.id); + expect(workItem3Details.parent).toBe(workItem1.id); + }); + + it("should add work items to cycle", async () => { + await client.cycles.addWorkItemsToCycle(e2eConfig.workspaceSlug, project.id, cycle.id, [ + workItem1.id, + workItem2.id, + ]); + + const workItemsInCycle = await client.cycles.listWorkItemsInCycle(e2eConfig.workspaceSlug, project.id, cycle.id); + expect(workItemsInCycle.results.length).toBeGreaterThan(0); + expect(workItemsInCycle.results.find((w) => w.id === workItem1.id)).toBeDefined(); + expect(workItemsInCycle.results.find((w) => w.id === workItem2.id)).toBeDefined(); + }); + + it("should add work items to module", async () => { + await client.modules.addWorkItemsToModule(e2eConfig.workspaceSlug, project.id, module.id, [ + workItem1.id, + workItem2.id, + ]); + + const workItemsInModule = await client.modules.listWorkItemsInModule( + e2eConfig.workspaceSlug, + project.id, + module.id + ); + expect(workItemsInModule.results.length).toBeGreaterThan(0); + expect(workItemsInModule.results.find((w) => w.id === workItem1.id)).toBeDefined(); + expect(workItemsInModule.results.find((w) => w.id === workItem2.id)).toBeDefined(); + }); + + it("should remove work item from module", async () => { + await client.modules.removeWorkItemFromModule(e2eConfig.workspaceSlug, project.id, module.id, workItem1.id); + + const workItemsInModuleAfterRemoval = await client.modules.listWorkItemsInModule( + e2eConfig.workspaceSlug, + project.id, + module.id + ); + expect(workItemsInModuleAfterRemoval.results.length).toBe(1); + expect(workItemsInModuleAfterRemoval.results.find((w) => w.id === workItem2.id)).toBeDefined(); + expect(workItemsInModuleAfterRemoval.results.find((w) => w.id === workItem1.id)).toBeUndefined(); + }); + + it("should remove work item from cycle", async () => { + await client.cycles.removeWorkItemFromCycle(e2eConfig.workspaceSlug, project.id, cycle.id, workItem1.id); + + const workItemsInCycleAfterRemoval = await client.cycles.listWorkItemsInCycle( + e2eConfig.workspaceSlug, + project.id, + cycle.id + ); + expect(workItemsInCycleAfterRemoval.results.length).toBe(1); + expect(workItemsInCycleAfterRemoval.results.find((w) => w.id === workItem2.id)).toBeDefined(); + expect(workItemsInCycleAfterRemoval.results.find((w) => w.id === workItem1.id)).toBeUndefined(); + }); + + afterAll(async () => { + console.log("Deleting project: ", project.name); + await client.projects.delete(e2eConfig.workspaceSlug, project.id); + }); +}); diff --git a/tests/helpers/test-utils.ts b/tests/helpers/test-utils.ts new file mode 100644 index 0000000..dfb45ea --- /dev/null +++ b/tests/helpers/test-utils.ts @@ -0,0 +1,31 @@ +import { PlaneClient } from "../../src/client/plane-client"; + +/** + * Creates a configured PlaneClient instance for testing + * @returns PlaneClient instance with test configuration + */ +export function createTestClient(): PlaneClient { + return new PlaneClient({ + apiKey: process.env.PLANE_API_KEY!, + baseUrl: process.env.PLANE_BASE_URL!, + }); +} + +/** + * Waits for a given number of seconds + * @param seconds - The number of seconds to wait + * @returns A promise that resolves after the given number of seconds + */ +export function wait(seconds = 60): Promise { + return new Promise((resolve) => setTimeout(resolve, seconds * 1000)); +} + +/** + * Randomizes a name by appending a random string to the end + * @param name - The name to randomize + * @param length - The length of the random string to append + * @returns The randomized name + */ +export function randomizeName(prefix: string = ""): string { + return prefix + Math.random().toString(36).substring(2, 10); +} diff --git a/tests/unit/cycle.test.ts b/tests/unit/cycle.test.ts index ca407d7..678f548 100644 --- a/tests/unit/cycle.test.ts +++ b/tests/unit/cycle.test.ts @@ -103,6 +103,7 @@ async function createCycle(client: PlaneClient, workspaceSlug: string, projectId name: "Test Cycle", description: "Test Cycle Description", owned_by: config.userId, + project_id: projectId, }); } diff --git a/tests/unit/module.test.ts b/tests/unit/module.test.ts index ab31f1a..f0e13b9 100644 --- a/tests/unit/module.test.ts +++ b/tests/unit/module.test.ts @@ -83,7 +83,7 @@ async function addWorkItemToModule( moduleId: string, workItemId: string ) { - return await client.modules.addWorkItemToModule(workspaceSlug, projectId, moduleId, [workItemId]); + return await client.modules.addWorkItemsToModule(workspaceSlug, projectId, moduleId, [workItemId]); } async function listWorkItemsInModule(client: PlaneClient, workspaceSlug: string, projectId: string, moduleId: string) { return await client.modules.listWorkItemsInModule(workspaceSlug, projectId, moduleId); diff --git a/tests/unit/setup.ts b/tests/unit/setup.ts deleted file mode 100644 index cb94b9f..0000000 --- a/tests/unit/setup.ts +++ /dev/null @@ -1,43 +0,0 @@ -// Jest setup file for global test configuration -import { config } from './unit/constants'; - -// Set up global test configuration -beforeAll(() => { - // Verify required environment variables are set - const requiredEnvVars = [ - 'PLANE_API_KEY', - 'PLANE_BASE_URL', - 'TEST_WORKSPACE_SLUG', - 'TEST_PROJECT_ID', - 'TEST_USER_ID', - 'TEST_WORK_ITEM_ID', - 'TEST_WORK_ITEM_ID_2', - 'TEST_CUSTOMER_ID', - 'TEST_WORK_ITEM_TYPE_ID', - 'TEST_CUSTOM_TEXT_PROPERTY_ID' - ]; - - const missingVars = requiredEnvVars.filter(varName => !process.env[varName]); - - if (missingVars.length > 0) { - throw new Error(`Missing required environment variables: ${missingVars.join(', ')}`); - } - - console.log('✅ All required environment variables are set'); - console.log(`📋 Testing workspace: ${config.workspaceSlug}`); -}); - -// Global test timeout -jest.setTimeout(30000); - -// Suppress console.log during tests unless in verbose mode -if (!process.env.JEST_VERBOSE) { - global.console = { - ...console, - log: jest.fn(), - debug: jest.fn(), - info: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - }; -} \ No newline at end of file From 19d18e7089a76d81e56ab68917db943a511003e2 Mon Sep 17 00:00:00 2001 From: Surya Prashanth Date: Tue, 28 Oct 2025 20:44:36 +0530 Subject: [PATCH 5/6] add jest and tsconfig.jest files --- jest.config.js | 25 +++++++++++++++++++++++++ tsconfig.jest.json | 29 +++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 jest.config.js create mode 100644 tsconfig.jest.json diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..5e8ed55 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,25 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + roots: ['/tests/e2e'], + testMatch: [ + '**/__tests__/**/*.ts', + '**/?(*.)+(spec).ts' + ], + transform: { + '^.+\\.ts$': ['ts-jest', { + tsconfig: 'tsconfig.jest.json' + }], + }, + collectCoverageFrom: [ + 'src/**/*.ts', + '!src/**/*.d.ts', + '!src/**/*.spec.ts' + ], + coverageDirectory: 'coverage', + coverageReporters: ['text', 'lcov', 'html'], + testTimeout: 30000, // 30 seconds timeout for API tests + verbose: true, + // Allow tests to run in parallel but with some control + maxWorkers: 1, // Run tests sequentially to avoid API rate limits +}; \ No newline at end of file diff --git a/tsconfig.jest.json b/tsconfig.jest.json new file mode 100644 index 0000000..686ed25 --- /dev/null +++ b/tsconfig.jest.json @@ -0,0 +1,29 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "outDir": "./dist", + "rootDir": "./", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "resolveJsonModule": true, + "types": ["jest", "node"] + }, + "include": [ + "src/**/*", + "tests/e2e/**/*" + ], + "exclude": [ + "node_modules", + "dist" + ] +} \ No newline at end of file From aa65bec04e66836b5accb4785e3ae1c1088ee4ca Mon Sep 17 00:00:00 2001 From: Surya Prashanth Date: Wed, 29 Oct 2025 17:01:01 +0530 Subject: [PATCH 6/6] feat: add unit tests using jest for all entities --- jest.config.js | 4 +- package.json | 6 +- src/api/Customers/Properties.ts | 42 +- src/api/Customers/Requests.ts | 30 +- src/api/Customers/index.ts | 69 +-- src/api/Links.ts | 13 +- src/api/WorkItemTypes.ts | 11 +- src/api/WorkItems/Comments.ts | 15 +- src/api/WorkItems/Relations.ts | 6 +- src/api/WorkItems/index.ts | 62 +-- src/models/Customer.ts | 17 + tests/e2e/project.spec.ts | 179 -------- tests/helpers/conditional-tests.ts | 14 + tests/unit/README.md | 78 +++- tests/unit/customers/customers.test.ts | 107 ++--- .../unit/customers/properties-options.test.ts | 206 +++++---- tests/unit/customers/requests.test.ts | 128 +++--- tests/unit/customers/work-items.test.ts | 83 ++-- tests/unit/cycle.test.ts | 325 +++++++------- tests/unit/epic.test.ts | 55 +-- tests/unit/intake.test.ts | 135 +++--- tests/unit/label.test.ts | 108 ++--- tests/unit/module.test.ts | 173 ++++---- tests/unit/oauth.test.ts | 95 ++-- tests/unit/page.test.ts | 108 ++--- tests/unit/project.test.ts | 119 ++--- tests/unit/run-all.test.ts | 70 --- tests/unit/state.test.ts | 113 ++--- .../properties-options.test.ts | 405 ++++++------------ .../work-item-types/properties-values.test.ts | 153 +++---- tests/unit/work-item-types/types.test.ts | 130 +++--- tests/unit/work-items/activities.test.ts | 77 ++-- tests/unit/work-items/comments.test.ts | 122 +++--- tests/unit/work-items/links.test.ts | 124 +++--- tests/unit/work-items/relations.test.ts | 108 +++-- tests/unit/work-items/work-items.test.ts | 185 ++++---- tests/unit/work-items/work-logs.test.ts | 108 +++-- 37 files changed, 1628 insertions(+), 2155 deletions(-) delete mode 100644 tests/e2e/project.spec.ts create mode 100644 tests/helpers/conditional-tests.ts delete mode 100644 tests/unit/run-all.test.ts diff --git a/jest.config.js b/jest.config.js index 5e8ed55..e0f397e 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,10 +1,10 @@ module.exports = { preset: 'ts-jest', testEnvironment: 'node', - roots: ['/tests/e2e'], + roots: ['/tests'], testMatch: [ '**/__tests__/**/*.ts', - '**/?(*.)+(spec).ts' + '**/?(*.)+(spec|test).ts' ], transform: { '^.+\\.ts$': ['ts-jest', { diff --git a/package.json b/package.json index dfd87e7..d337657 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,11 @@ "build": "tsc", "dev": "tsc --watch", "test": "jest", - "test:unit": "ts-node tests/unit/run-all.test.ts", + "test:unit": "jest --testPathPattern=tests/unit", + "test:e2e": "jest --testPathPattern=tests/e2e", + "test:all": "pnpm test:unit && pnpm test:e2e", + "test:watch": "jest --watch", + "test:coverage": "jest --coverage", "lint": "eslint src/**/*.ts", "format": "prettier --write src/**/*.ts", "clean": "rm -rf dist" diff --git a/src/api/Customers/Properties.ts b/src/api/Customers/Properties.ts index 8c42372..3c9744a 100644 --- a/src/api/Customers/Properties.ts +++ b/src/api/Customers/Properties.ts @@ -8,7 +8,9 @@ import { ListCustomerPropertiesParams, CreateCustomerPropertyRequest, UpdateCustomerPropertyRequest, + CustomPropertyValueResponse, } from "../../models/Customer"; +import { PaginatedResponse } from "../../models/common"; /** * Customer Properties API resource @@ -27,11 +29,8 @@ export class Properties extends BaseResource { async listPropertyDefinitions( workspaceSlug: string, params?: ListCustomerPropertiesParams - ): Promise { - return this.get( - `/workspaces/${workspaceSlug}/customer-properties/`, - params - ); + ): Promise> { + return this.get>(`/workspaces/${workspaceSlug}/customer-properties/`, params); } /** @@ -41,22 +40,14 @@ export class Properties extends BaseResource { workspaceSlug: string, createProperty: CreateCustomerPropertyRequest ): Promise { - return this.post( - `/workspaces/${workspaceSlug}/customer-properties/`, - createProperty - ); + return this.post(`/workspaces/${workspaceSlug}/customer-properties/`, createProperty); } /** * Retrieve customer property */ - async retrievePropertyDefinition( - workspaceSlug: string, - propertyId: string - ): Promise { - return this.get( - `/workspaces/${workspaceSlug}/customer-properties/${propertyId}/` - ); + async retrievePropertyDefinition(workspaceSlug: string, propertyId: string): Promise { + return this.get(`/workspaces/${workspaceSlug}/customer-properties/${propertyId}/`); } /** @@ -76,13 +67,8 @@ export class Properties extends BaseResource { /** * Delete customer property */ - async deletePropertyDefinition( - workspaceSlug: string, - propertyId: string - ): Promise { - return this.httpDelete( - `/workspaces/${workspaceSlug}/customer-properties/${propertyId}/` - ); + async deletePropertyDefinition(workspaceSlug: string, propertyId: string): Promise { + return this.httpDelete(`/workspaces/${workspaceSlug}/customer-properties/${propertyId}/`); } // ===== CUSTOMER PROPERTY VALUES API METHODS ===== @@ -94,8 +80,8 @@ export class Properties extends BaseResource { workspaceSlug: string, customerId: string, params?: ListCustomerPropertyValuesParams - ): Promise { - return this.get( + ): Promise { + return this.get( `/workspaces/${workspaceSlug}/customers/${customerId}/property-values/`, params ); @@ -104,11 +90,7 @@ export class Properties extends BaseResource { /** * Get single property value */ - async retrieveValue( - workspaceSlug: string, - customerId: string, - propertyId: string - ): Promise { + async retrieveValue(workspaceSlug: string, customerId: string, propertyId: string): Promise { return this.get( `/workspaces/${workspaceSlug}/customers/${customerId}/property-values/${propertyId}/` ); diff --git a/src/api/Customers/Requests.ts b/src/api/Customers/Requests.ts index f19b347..e6115a0 100644 --- a/src/api/Customers/Requests.ts +++ b/src/api/Customers/Requests.ts @@ -6,6 +6,7 @@ import { UpdateCustomerRequest, ListCustomerRequestsParams, } from "../../models/Customer"; +import { PaginatedResponse } from "../../models/common"; /** * Customer Requests API resource @@ -23,8 +24,8 @@ export class Requests extends BaseResource { workspaceSlug: string, customerId: string, params?: ListCustomerRequestsParams - ): Promise { - return this.get( + ): Promise> { + return this.get>( `/workspaces/${workspaceSlug}/customers/${customerId}/requests/`, params ); @@ -38,23 +39,14 @@ export class Requests extends BaseResource { customerId: string, createRequest: CreateCustomerRequest ): Promise { - return this.post( - `/workspaces/${workspaceSlug}/customers/${customerId}/requests/`, - createRequest - ); + return this.post(`/workspaces/${workspaceSlug}/customers/${customerId}/requests/`, createRequest); } /** * Retrieve customer request */ - async retrieve( - workspaceSlug: string, - customerId: string, - requestId: string - ): Promise { - return this.get( - `/workspaces/${workspaceSlug}/customers/${customerId}/requests/${requestId}/` - ); + async retrieve(workspaceSlug: string, customerId: string, requestId: string): Promise { + return this.get(`/workspaces/${workspaceSlug}/customers/${customerId}/requests/${requestId}/`); } /** @@ -75,13 +67,7 @@ export class Requests extends BaseResource { /** * Delete customer request */ - async delete( - workspaceSlug: string, - customerId: string, - requestId: string - ): Promise { - return this.httpDelete( - `/workspaces/${workspaceSlug}/customers/${customerId}/requests/${requestId}/` - ); + async delete(workspaceSlug: string, customerId: string, requestId: string): Promise { + return this.httpDelete(`/workspaces/${workspaceSlug}/customers/${customerId}/requests/${requestId}/`); } } diff --git a/src/api/Customers/index.ts b/src/api/Customers/index.ts index 21e1e28..f0bafcf 100644 --- a/src/api/Customers/index.ts +++ b/src/api/Customers/index.ts @@ -5,9 +5,11 @@ import { CreateCustomer, UpdateCustomer, ListCustomersParams, + LinkIssuesToCustomerResponse, } from "../../models/Customer"; import { Properties } from "./Properties"; import { Requests } from "./Requests"; +import { PaginatedResponse } from "../../models/common"; /** * Customers API resource @@ -27,59 +29,36 @@ export class Customers extends BaseResource { /** * Create a new customer */ - async create( - workspaceSlug: string, - createCustomer: CreateCustomer - ): Promise { - return this.post( - `/workspaces/${workspaceSlug}/customers/`, - createCustomer - ); + async create(workspaceSlug: string, createCustomer: CreateCustomer): Promise { + return this.post(`/workspaces/${workspaceSlug}/customers/`, createCustomer); } /** * Retrieve a customer by ID */ async retrieve(workspaceSlug: string, customerId: string): Promise { - return this.get( - `/workspaces/${workspaceSlug}/customers/${customerId}/` - ); + return this.get(`/workspaces/${workspaceSlug}/customers/${customerId}/`); } /** * Update a customer */ - async update( - workspaceSlug: string, - customerId: string, - updateCustomer: UpdateCustomer - ): Promise { - return this.patch( - `/workspaces/${workspaceSlug}/customers/${customerId}/`, - updateCustomer - ); + async update(workspaceSlug: string, customerId: string, updateCustomer: UpdateCustomer): Promise { + return this.patch(`/workspaces/${workspaceSlug}/customers/${customerId}/`, updateCustomer); } /** * Delete a customer */ async delete(workspaceSlug: string, customerId: string): Promise { - return this.httpDelete( - `/workspaces/${workspaceSlug}/customers/${customerId}/` - ); + return this.httpDelete(`/workspaces/${workspaceSlug}/customers/${customerId}/`); } /** * List customers with optional filtering */ - async list( - workspaceSlug: string, - params?: ListCustomersParams - ): Promise { - return this.get( - `/workspaces/${workspaceSlug}/customers/`, - params - ); + async list(workspaceSlug: string, params?: ListCustomersParams): Promise> { + return this.get>(`/workspaces/${workspaceSlug}/customers/`, params); } // ===== CUSTOMER ISSUES API METHODS ===== @@ -87,13 +66,8 @@ export class Customers extends BaseResource { /** * List customer issues */ - async listCustomerIssues( - workspaceSlug: string, - customerId: string - ): Promise { - return this.get( - `/workspaces/${workspaceSlug}/customers/${customerId}/issues/` - ); + async listCustomerIssues(workspaceSlug: string, customerId: string): Promise { + return this.get(`/workspaces/${workspaceSlug}/customers/${customerId}/issues/`); } /** @@ -103,23 +77,16 @@ export class Customers extends BaseResource { workspaceSlug: string, customerId: string, issueIds: string[] - ): Promise { - return this.post( - `/workspaces/${workspaceSlug}/customers/${customerId}/issues/`, - { issue_ids: issueIds } - ); + ): Promise { + return this.post(`/workspaces/${workspaceSlug}/customers/${customerId}/issues/`, { + issue_ids: issueIds, + }); } /** * Unlink issue from customer */ - async unlinkIssueFromCustomer( - workspaceSlug: string, - customerId: string, - issueId: string - ): Promise { - return this.httpDelete( - `/workspaces/${workspaceSlug}/customers/${customerId}/issues/${issueId}/` - ); + async unlinkIssueFromCustomer(workspaceSlug: string, customerId: string, issueId: string): Promise { + return this.httpDelete(`/workspaces/${workspaceSlug}/customers/${customerId}/issues/${issueId}/`); } } diff --git a/src/api/Links.ts b/src/api/Links.ts index c0cb45f..8ce7581 100644 --- a/src/api/Links.ts +++ b/src/api/Links.ts @@ -1,6 +1,7 @@ import { BaseResource } from "./BaseResource"; import { Configuration } from "../Configuration"; import { Link, CreateLink, UpdateLink, ListLinksParams } from "../models/Link"; +import { PaginatedResponse } from "../models/common"; /** * Links API resource @@ -54,7 +55,15 @@ export class Links extends BaseResource { /** * List links for a work item with optional filtering */ - async list(workspaceSlug: string, projectId: string, issueId: string, params?: ListLinksParams): Promise { - return this.get(`/workspaces/${workspaceSlug}/projects/${projectId}/work-items/${issueId}/links/`, params); + async list( + workspaceSlug: string, + projectId: string, + issueId: string, + params?: ListLinksParams + ): Promise> { + return this.get>( + `/workspaces/${workspaceSlug}/projects/${projectId}/work-items/${issueId}/links/`, + params + ); } } diff --git a/src/api/WorkItemTypes.ts b/src/api/WorkItemTypes.ts index f2209cc..fbabfa4 100644 --- a/src/api/WorkItemTypes.ts +++ b/src/api/WorkItemTypes.ts @@ -66,14 +66,7 @@ export class WorkItemTypes extends BaseResource { /** * List work item types with optional filtering */ - async list( - workspaceSlug: string, - projectId: string, - params?: ListWorkItemTypesParams - ): Promise> { - return this.get>( - `/workspaces/${workspaceSlug}/projects/${projectId}/work-item-types/`, - params - ); + async list(workspaceSlug: string, projectId: string, params?: ListWorkItemTypesParams): Promise { + return this.get(`/workspaces/${workspaceSlug}/projects/${projectId}/work-item-types/`, params); } } diff --git a/src/api/WorkItems/Comments.ts b/src/api/WorkItems/Comments.ts index cd5a025..268ac36 100644 --- a/src/api/WorkItems/Comments.ts +++ b/src/api/WorkItems/Comments.ts @@ -1,10 +1,12 @@ import { BaseResource } from "../BaseResource"; import { Configuration } from "../../Configuration"; import { + ListCommentsParams, WorkItemComment, WorkItemCommentCreateRequest, WorkItemCommentUpdateRequest, } from "../../models/Comment"; +import { PaginatedResponse } from "../../models/common"; /** * WorkItemComments API resource @@ -36,9 +38,9 @@ export class Comments extends BaseResource { workspaceSlug: string, projectId: string, workItemId: string, - params?: any - ): Promise { - return this.get( + params?: ListCommentsParams + ): Promise> { + return this.get>( `/workspaces/${workspaceSlug}/projects/${projectId}/work-items/${workItemId}/comments/`, params ); @@ -78,12 +80,7 @@ export class Comments extends BaseResource { /** * Delete a comment */ - async delete( - workspaceSlug: string, - projectId: string, - workItemId: string, - commentId: string - ): Promise { + async delete(workspaceSlug: string, projectId: string, workItemId: string, commentId: string): Promise { return this.httpDelete( `/workspaces/${workspaceSlug}/projects/${projectId}/work-items/${workItemId}/comments/${commentId}/` ); diff --git a/src/api/WorkItems/Relations.ts b/src/api/WorkItems/Relations.ts index bd9a9cc..b798f84 100644 --- a/src/api/WorkItems/Relations.ts +++ b/src/api/WorkItems/Relations.ts @@ -48,11 +48,7 @@ export class Relations extends BaseResource { /** * List relations for a work item */ - async list( - workspaceSlug: string, - projectId: string, - workItemId: string - ): Promise { + async list(workspaceSlug: string, projectId: string, workItemId: string): Promise { return this.get( `/workspaces/${workspaceSlug}/projects/${projectId}/work-items/${workItemId}/relations/` ); diff --git a/src/api/WorkItems/index.ts b/src/api/WorkItems/index.ts index e81eac3..851f508 100644 --- a/src/api/WorkItems/index.ts +++ b/src/api/WorkItems/index.ts @@ -42,23 +42,12 @@ export class WorkItems extends BaseResource { /** * Create a new work item */ - async create( - workspaceSlug: string, - projectId: string, - createWorkItem: CreateWorkItem - ): Promise { - return this.post( - `/workspaces/${workspaceSlug}/projects/${projectId}/work-items/`, - createWorkItem - ); + async create(workspaceSlug: string, projectId: string, createWorkItem: CreateWorkItem): Promise { + return this.post(`/workspaces/${workspaceSlug}/projects/${projectId}/work-items/`, createWorkItem); } // method overloads - async retrieve( - workspaceSlug: string, - projectId: string, - workItemId: string - ): Promise; + async retrieve(workspaceSlug: string, projectId: string, workItemId: string): Promise; async retrieve( workspaceSlug: string, @@ -76,10 +65,9 @@ export class WorkItems extends BaseResource { workItemId: string, expand?: E[] ): Promise> { - return this.get>( - `/workspaces/${workspaceSlug}/projects/${projectId}/work-items/${workItemId}/`, - { expand: expand?.join(",") } - ); + return this.get>(`/workspaces/${workspaceSlug}/projects/${projectId}/work-items/${workItemId}/`, { + expand: expand?.join(","), + }); } /** @@ -100,14 +88,8 @@ export class WorkItems extends BaseResource { /** * Delete a work item */ - async delete( - workspaceSlug: string, - projectId: string, - workItemId: string - ): Promise { - return this.httpDelete( - `/workspaces/${workspaceSlug}/projects/${projectId}/work-items/${workItemId}/` - ); + async delete(workspaceSlug: string, projectId: string, workItemId: string): Promise { + return this.httpDelete(`/workspaces/${workspaceSlug}/projects/${projectId}/work-items/${workItemId}/`); } /** @@ -125,10 +107,7 @@ export class WorkItems extends BaseResource { } // method overloads - async retrieveByIdentifier( - workspaceSlug: string, - identifier: string - ): Promise; + async retrieveByIdentifier(workspaceSlug: string, identifier: string): Promise; async retrieveByIdentifier( workspaceSlug: string, @@ -142,24 +121,19 @@ export class WorkItems extends BaseResource { identifier: string, expand?: E[] ): Promise | WorkItemBase> { - return this.get>( - `/workspaces/${workspaceSlug}/work-items/${identifier}/`, - { expand: expand?.join(",") } - ); + return this.get>(`/workspaces/${workspaceSlug}/work-items/${identifier}/`, { + expand: expand?.join(","), + }); } /** * Search work items */ - async search( - workspaceSlug: string, - projectId: string, - query: string, - params?: any - ): Promise { - return this.get( - `/workspaces/${workspaceSlug}/work-items/search/`, - { ...params, search: query, project: projectId } - ); + async search(workspaceSlug: string, query: string, projectId?: string, params?: any): Promise { + return this.get(`/workspaces/${workspaceSlug}/work-items/search/`, { + ...params, + search: query, + project: projectId, + }); } } diff --git a/src/models/Customer.ts b/src/models/Customer.ts index 46ef476..ea30f36 100644 --- a/src/models/Customer.ts +++ b/src/models/Customer.ts @@ -39,6 +39,10 @@ export interface CustomerPropertyValue extends BaseModel { [key: string]: any; } +export interface CustomPropertyValueResponse { + [propertyId: string]: any[]; +} + export type UpdateCustomerPropertyValue = { values: any[]; }; @@ -140,3 +144,16 @@ export interface UpdateCustomerPropertyRequest { created_by?: string; updated_by?: string; } + +export interface LinkIssuesToCustomerResponse { + message: string; + linked_issues: LinkedIssue[]; +} + +export interface LinkedIssue { + id: string; + name: string; + sequence_id: number; + project_id: string; + project__identifier: string; +} diff --git a/tests/e2e/project.spec.ts b/tests/e2e/project.spec.ts deleted file mode 100644 index b4c5119..0000000 --- a/tests/e2e/project.spec.ts +++ /dev/null @@ -1,179 +0,0 @@ -import { createTestClient, randomizeName, wait } from "../helpers/test-utils"; -import { e2eConfig } from "./config"; -import { Project, Cycle, Module, WorkItem } from "../../src/models"; - -describe("End to End Project Test", () => { - // Shared state across tests - let client: ReturnType; - let userId: string; - let project: Project; - let cycle: Cycle; - let module: Module; - let workItem1: WorkItem; - let workItem2: WorkItem; - let workItem3: WorkItem; - - beforeAll(async () => { - // Initialize client and create prerequisites for all tests - client = createTestClient(); - - // Get current user - needed for assignees and cycle owners - const me = await client.users.me(); - userId = me.id!; - - // Create project - all tests depend on this - const projectName = randomizeName(); - project = await client.projects.create(e2eConfig.workspaceSlug, { - name: projectName, - id: projectName.slice(0, 5).toUpperCase(), - }); - }); - - it("should create and list cycles", async () => { - const cycleName = randomizeName("Test Cycle"); - cycle = await client.cycles.create(e2eConfig.workspaceSlug, project.id, { - name: cycleName, - description: "Test Cycle Description", - // YYYY-MM-DD format - start_date: new Date().toISOString().split("T")[0], - // YYYY-MM-DD format - end_date: new Date(new Date().setDate(new Date().getDate() + 14)).toISOString().split("T")[0], - owned_by: userId, - project_id: project.id, - }); - - expect(cycle).toBeDefined(); - expect(cycle.id).toBeDefined(); - expect(cycle.name).toBe(cycleName); - - const cycles = await client.cycles.list(e2eConfig.workspaceSlug, project.id); - expect(cycles.results.length).toBeGreaterThan(0); - expect(cycles.results.find((c) => c.name === cycle.name)).toBeDefined(); - }); - - it("should create and list modules", async () => { - const moduleName = randomizeName("Test Module"); - module = await client.modules.create(e2eConfig.workspaceSlug, project.id, { - name: moduleName, - description: "Test Module Description", - }); - - expect(module).toBeDefined(); - expect(module.id).toBeDefined(); - expect(module.name).toBe(moduleName); - - const modules = await client.modules.list(e2eConfig.workspaceSlug, project.id); - expect(modules.results.length).toBeGreaterThan(0); - expect(modules.results.find((m) => m.name === module.name)).toBeDefined(); - }); - - it("should create work items with assignees", async () => { - workItem1 = await client.workItems.create(e2eConfig.workspaceSlug, project.id, { - name: randomizeName("Test Work Item 1"), - description_html: "

Test Work Item 1 Description

", - assignees: [userId], - }); - - expect(workItem1).toBeDefined(); - expect(workItem1.id).toBeDefined(); - expect(workItem1.assignees).toBeDefined(); - - workItem2 = await client.workItems.create(e2eConfig.workspaceSlug, project.id, { - name: randomizeName("Test Work Item 2"), - description_html: "

Test Work Item 2 Description

", - assignees: [userId], - }); - - expect(workItem2).toBeDefined(); - expect(workItem2.id).toBeDefined(); - expect(workItem2.assignees).toHaveLength(1); - - const workItems = await client.workItems.list(e2eConfig.workspaceSlug, project.id); - expect(workItems.results.length).toBeGreaterThan(0); - }); - - it("should create work item relations", async () => { - await client.workItems.relations.create(e2eConfig.workspaceSlug, project.id, workItem1.id, { - relation_type: "relates_to", - issues: [workItem2.id], - }); - - const relations = await client.workItems.relations.list(e2eConfig.workspaceSlug, project.id, workItem1.id); - expect(relations.relates_to).toBeDefined(); - expect(relations.relates_to[0]).toBe(workItem2.id); - }); - - it("should create work item with parent relationship", async () => { - workItem3 = await client.workItems.create(e2eConfig.workspaceSlug, project.id, { - name: randomizeName("Test Work Item 3"), - description_html: "

Test Work Item 3 Description

", - assignees: [userId], - parent: workItem1.id, - }); - - expect(workItem3).toBeDefined(); - expect(workItem3.id).toBeDefined(); - - const workItem3Details = await client.workItems.retrieve(e2eConfig.workspaceSlug, project.id, workItem3.id); - expect(workItem3Details.parent).toBe(workItem1.id); - }); - - it("should add work items to cycle", async () => { - await client.cycles.addWorkItemsToCycle(e2eConfig.workspaceSlug, project.id, cycle.id, [ - workItem1.id, - workItem2.id, - ]); - - const workItemsInCycle = await client.cycles.listWorkItemsInCycle(e2eConfig.workspaceSlug, project.id, cycle.id); - expect(workItemsInCycle.results.length).toBeGreaterThan(0); - expect(workItemsInCycle.results.find((w) => w.id === workItem1.id)).toBeDefined(); - expect(workItemsInCycle.results.find((w) => w.id === workItem2.id)).toBeDefined(); - }); - - it("should add work items to module", async () => { - await client.modules.addWorkItemsToModule(e2eConfig.workspaceSlug, project.id, module.id, [ - workItem1.id, - workItem2.id, - ]); - - const workItemsInModule = await client.modules.listWorkItemsInModule( - e2eConfig.workspaceSlug, - project.id, - module.id - ); - expect(workItemsInModule.results.length).toBeGreaterThan(0); - expect(workItemsInModule.results.find((w) => w.id === workItem1.id)).toBeDefined(); - expect(workItemsInModule.results.find((w) => w.id === workItem2.id)).toBeDefined(); - }); - - it("should remove work item from module", async () => { - await client.modules.removeWorkItemFromModule(e2eConfig.workspaceSlug, project.id, module.id, workItem1.id); - - const workItemsInModuleAfterRemoval = await client.modules.listWorkItemsInModule( - e2eConfig.workspaceSlug, - project.id, - module.id - ); - expect(workItemsInModuleAfterRemoval.results.length).toBe(1); - expect(workItemsInModuleAfterRemoval.results.find((w) => w.id === workItem2.id)).toBeDefined(); - expect(workItemsInModuleAfterRemoval.results.find((w) => w.id === workItem1.id)).toBeUndefined(); - }); - - it("should remove work item from cycle", async () => { - await client.cycles.removeWorkItemFromCycle(e2eConfig.workspaceSlug, project.id, cycle.id, workItem1.id); - - const workItemsInCycleAfterRemoval = await client.cycles.listWorkItemsInCycle( - e2eConfig.workspaceSlug, - project.id, - cycle.id - ); - expect(workItemsInCycleAfterRemoval.results.length).toBe(1); - expect(workItemsInCycleAfterRemoval.results.find((w) => w.id === workItem2.id)).toBeDefined(); - expect(workItemsInCycleAfterRemoval.results.find((w) => w.id === workItem1.id)).toBeUndefined(); - }); - - afterAll(async () => { - console.log("Deleting project: ", project.name); - await client.projects.delete(e2eConfig.workspaceSlug, project.id); - }); -}); diff --git a/tests/helpers/conditional-tests.ts b/tests/helpers/conditional-tests.ts new file mode 100644 index 0000000..a176b97 --- /dev/null +++ b/tests/helpers/conditional-tests.ts @@ -0,0 +1,14 @@ +/** + * Test utilities for conditional test execution based on configuration + */ + +/** + * Creates a conditional describe block that skips all tests if condition is false + * @param condition - Boolean condition to check + * @param name - Name of the test suite + * @param fn - Test suite function + * @returns Jest describe block (either normal or skipped) + */ +export const describeIf = (condition: boolean, name: string, fn: () => void) => { + return condition ? describe(name, fn) : describe.skip(name, fn); +}; diff --git a/tests/unit/README.md b/tests/unit/README.md index cc5f016..0be81a0 100644 --- a/tests/unit/README.md +++ b/tests/unit/README.md @@ -1,12 +1,20 @@ -# Test Configuration +# Unit Tests -This directory contains test files and configuration for the Plane Node SDK. +This directory contains Jest-based unit tests for the Plane Node SDK. All tests use conditional execution patterns that gracefully skip tests when required configuration is not available. -## Test Configuration Setup +## Test Structure -The test constants are configurable through environment variables. This allows each developer to use their own test environment without modifying shared files. +All tests follow a consistent pattern: +- Written using Jest with `describe`, `it`, `beforeAll`, and `afterAll` blocks +- Use conditional `describeIf` helper to skip tests when required config is missing +- Include proper cleanup in `afterAll` hooks to remove test data +- Use `randomizeName()` utility to generate unique test data -### Option 1: Environment Variables (Recommended) +## Test Configuration + +Tests require environment variables to run. If these are not set, the tests will be skipped automatically (no failures). + +### Required Environment Variables Set the following environment variables before running tests: @@ -21,31 +29,63 @@ export TEST_WORK_ITEM_TYPE_ID="your-work-item-type-id" export TEST_CUSTOM_TEXT_PROPERTY_ID="your-custom-text-property-id" ``` -### Option 2: .env.test File +### Using .env File -Create a `.env.test` file in the project root with your configuration: +Create a `.env` file in the project root with your configuration: ```bash # Copy the example and update with your values -cp env.example .env.test +cp env.example .env ``` -Then update the values in `.env.test` with your test environment details. - -### Option 3: Direct File Modification - -If you prefer to modify the constants directly, edit `tests/constants.ts` and update the fallback values. Note that this will affect all developers, so use this option carefully. +Then update the values with your test environment details. ## Running Tests -After setting up your configuration, run the tests: - ```bash -npm test -# or +# Run all tests pnpm test + +# Run a specific test file +pnpm test label.test.ts + +# Run tests in a specific directory +pnpm test customers + +# Run tests matching a pattern +pnpm test work-items + +# Run tests in watch mode +pnpm test --watch + +# Run tests with coverage +pnpm test --coverage +``` + +## Test Organization + +``` +tests/unit/ +├── constants.ts # Test configuration +├── helpers/ +│ ├── conditional-tests.ts # Conditional describe helper +│ └── test-utils.ts # Test utilities +├── customers/ # Customer API tests +├── work-items/ # Work Items API tests +├── work-item-types/ # Work Item Types API tests +├── cycle.test.ts # Cycle API tests +├── epic.test.ts # Epic API tests +├── intake.test.ts # Intake API tests +├── label.test.ts # Label API tests +├── module.test.ts # Module API tests +├── oauth.test.ts # OAuth API tests +├── page.test.ts # Page API tests +├── project.test.ts # Project API tests +└── state.test.ts # State API tests ``` -## Default Values +## Test Behavior -The constants file includes default values that work with the current test environment. If you don't set environment variables, these defaults will be used. +- **With Config**: Tests run normally and verify API operations +- **Without Config**: Tests are skipped gracefully (shown as "skipped" in test output) +- **Cleanup**: All tests clean up created resources in `afterAll` hooks diff --git a/tests/unit/customers/customers.test.ts b/tests/unit/customers/customers.test.ts index cd7274d..5f9f55b 100644 --- a/tests/unit/customers/customers.test.ts +++ b/tests/unit/customers/customers.test.ts @@ -1,65 +1,74 @@ import { PlaneClient } from "../../../src/client/plane-client"; +import { Customer } from "../../../src/models/Customer"; import { config } from "../constants"; -import { createTestClient } from "../../helpers/test-utils"; +import { createTestClient, randomizeName } from "../../helpers/test-utils"; +import { describeIf as describe } from "../../helpers/conditional-tests"; -export async function testCustomers() { - const client = createTestClient(); +describe(!!config.workspaceSlug, "Customer API Tests", () => { + let client: PlaneClient; + let workspaceSlug: string; + let customer: Customer; - const workspaceSlug = config.workspaceSlug; - - if (!workspaceSlug) { - console.error("workspaceSlug is required"); - return; - } - - const customer = await createCustomer(client, workspaceSlug); - console.log("Created customer: ", customer); + beforeAll(async () => { + client = createTestClient(); + workspaceSlug = config.workspaceSlug; + }); - const retrievedCustomer = await retrieveCustomer(client, workspaceSlug, customer.id); - console.log("Retrieved customer: ", retrievedCustomer); + afterAll(async () => { + // Clean up created customer + if (customer?.id) { + try { + await client.customers.delete(workspaceSlug, customer.id); + } catch (error) { + console.warn("Failed to delete customer:", error); + } + } + }); - const updatedCustomer = await updateCustomer(client, workspaceSlug, customer.id); - console.log("Updated customer: ", updatedCustomer); + it("should create a customer", async () => { + customer = await client.customers.create(workspaceSlug, { + name: randomizeName("Test Customer"), + description: "Test Customer Description", + }); - const customers = await listCustomers(client, workspaceSlug); - console.log("Listed customers: ", customers); + expect(customer).toBeDefined(); + expect(customer.id).toBeDefined(); + expect(customer.name).toContain("Test Customer"); + expect(customer.description).toBe("Test Customer Description"); + }); - await deleteCustomer(client, workspaceSlug, customer.id); - console.log("Deleted customer: ", customer.id); -} + it("should retrieve a customer", async () => { + const retrievedCustomer = await client.customers.retrieve(workspaceSlug, customer.id!); -async function createCustomer(client: PlaneClient, workspaceSlug: string) { - const customer = await client.customers.create(workspaceSlug, { - name: `Test Customer ${new Date().getTime()}`, - description: "Test Customer Description", + expect(retrievedCustomer).toBeDefined(); + expect(retrievedCustomer.id).toBe(customer.id); + expect(retrievedCustomer.name).toBe(customer.name); + expect(retrievedCustomer.description).toBe(customer.description); }); - return customer; -} -async function retrieveCustomer(client: PlaneClient, workspaceSlug: string, customerId: string) { - const customer = await client.customers.retrieve(workspaceSlug, customerId); - return customer; -} + it("should update a customer", async () => { + const updatedCustomer = await client.customers.update(workspaceSlug, customer.id!, { + name: randomizeName("Updated Test Customer"), + description: "Updated Test Customer Description", + }); -async function updateCustomer(client: PlaneClient, workspaceSlug: string, customerId: string) { - return await client.customers.update(workspaceSlug, customerId, { - name: `Updated Test Customer ${new Date().getTime()}`, - description: "Updated Test Customer Description", + expect(updatedCustomer).toBeDefined(); + expect(updatedCustomer.id).toBe(customer.id); + expect(updatedCustomer.name).toContain("Updated Test Customer"); + expect(updatedCustomer.description).toBe("Updated Test Customer Description"); }); -} -async function listCustomers(client: PlaneClient, workspaceSlug: string) { - const customers = await client.customers.list(workspaceSlug, { - limit: 10, - offset: 0, - }); - return customers; -} + it("should list customers", async () => { + const customers = await client.customers.list(workspaceSlug, { + limit: 10, + offset: 0, + }); -async function deleteCustomer(client: PlaneClient, workspaceSlug: string, customerId: string) { - await client.customers.delete(workspaceSlug, customerId); -} + expect(customers).toBeDefined(); + expect(Array.isArray(customers.results)).toBe(true); + expect(customers.results.length).toBeGreaterThan(0); -if (require.main === module) { - testCustomers().catch(console.error); -} + const foundCustomer = customers.results.find((c) => c.id === customer.id); + expect(foundCustomer).toBeDefined(); + }); +}); diff --git a/tests/unit/customers/properties-options.test.ts b/tests/unit/customers/properties-options.test.ts index 6b7d6dd..a9a69d2 100644 --- a/tests/unit/customers/properties-options.test.ts +++ b/tests/unit/customers/properties-options.test.ts @@ -1,123 +1,115 @@ import { PlaneClient } from "../../../src/client/plane-client"; +import { CustomerProperty } from "../../../src/models/Customer"; import { config } from "../constants"; -import { createTestClient } from "../../helpers/test-utils"; - -export async function testCustomersPropertiesOptionsAndValues() { - const client = createTestClient(); - - const workspaceSlug = config.workspaceSlug; - const customerId = config.customerId; - - if (!workspaceSlug || !customerId) { - console.error("workspaceSlug and customerId are required"); - return; - } - - const customerProperty = await createCustomerProperty(client, workspaceSlug); - console.log("Created customer property: ", customerProperty); - - if (!customerProperty.id) { - throw new Error("Customer property ID is required"); - } +import { createTestClient, randomizeName } from "../../helpers/test-utils"; +import { describeIf as describe } from "../../helpers/conditional-tests"; + +describe(!!(config.workspaceSlug && config.customerId), "Customer Properties API Tests", () => { + let client: PlaneClient; + let workspaceSlug: string; + let customerId: string; + let customerProperty: CustomerProperty; + + beforeAll(async () => { + client = createTestClient(); + workspaceSlug = config.workspaceSlug; + customerId = config.customerId; + }); - const retrievedCustomerProperty = await retrieveCustomerProperty(client, workspaceSlug, customerProperty.id); - console.log("Retrieved customer property: ", retrievedCustomerProperty); + afterAll(async () => { + // Clean up created customer property + if (customerProperty?.id) { + try { + await client.customers.properties.deletePropertyDefinition(workspaceSlug, customerProperty.id); + } catch (error) { + console.warn("Failed to delete customer property:", error); + } + } + }); - const updatedCustomerProperty = await updateCustomerProperty(client, workspaceSlug, customerProperty.id); - console.log("Updated customer property: ", updatedCustomerProperty); + it("should create a customer property", async () => { + const name = randomizeName("test-customer-property"); + customerProperty = await client.customers.properties.createPropertyDefinition(workspaceSlug, { + name: name, + display_name: name, + description: "Test Customer Property Description", + property_type: "TEXT", + settings: { + display_format: "single-line", + }, + }); + + expect(customerProperty).toBeDefined(); + expect(customerProperty.id).toBeDefined(); + expect(customerProperty.name).toBe(name); + expect(customerProperty.description).toBe("Test Customer Property Description"); + }); - const customerProperties = await listCustomerProperties(client, workspaceSlug); - console.log("Listed customer properties: ", customerProperties); + it("should retrieve a customer property", async () => { + const retrievedCustomerProperty = await client.customers.properties.retrievePropertyDefinition( + workspaceSlug, + customerProperty.id! + ); - // before deleting we test the property values - const customerPropertyValue = await updateCustomerPropertyValue( - client, - workspaceSlug, - customerId, - customerProperty.id - ); - console.log("Updated customer property value: ", customerProperty.id, customerPropertyValue); + expect(retrievedCustomerProperty).toBeDefined(); + expect(retrievedCustomerProperty.id).toBe(customerProperty.id); + expect(retrievedCustomerProperty.name).toBe(customerProperty.name); + }); - await new Promise((resolve) => setTimeout(resolve, 1000)); + it("should update a customer property", async () => { + const updatedCustomerProperty = await client.customers.properties.updatePropertyDefinition( + workspaceSlug, + customerProperty.id!, + { + display_name: randomizeName("Updated Test Customer Property"), + description: "Updated Test Customer Property Description", + } + ); + + expect(updatedCustomerProperty).toBeDefined(); + expect(updatedCustomerProperty.id).toBe(customerProperty.id); + expect(updatedCustomerProperty.description).toBe("Updated Test Customer Property Description"); + }); - const allCustomerPropertyValues = await listCustomerPropertyValues(client, workspaceSlug, customerId); - console.log("Listed customer property values: ", allCustomerPropertyValues); + it("should list customer properties", async () => { + const customerProperties = await client.customers.properties.listPropertyDefinitions(workspaceSlug); - await new Promise((resolve) => setTimeout(resolve, 1000)); + expect(Array.isArray(customerProperties.results)).toBe(true); + expect(customerProperties.results.length).toBeGreaterThan(0); - const retrievedCustomerPropertyValue = await retrieveCustomerPropertyValue( - client, - workspaceSlug, - customerId, - customerProperty.id - ); - console.log("Retrieved customer property value: ", retrievedCustomerPropertyValue); + const foundProperty = customerProperties.results.find((p) => p.id === customerProperty.id); + expect(foundProperty).toBeDefined(); + }); - await new Promise((resolve) => setTimeout(resolve, 1000)); + it("should update a customer property value", async () => { + const customerPropertyValue = await client.customers.properties.updateValue( + workspaceSlug, + customerId, + customerProperty.id!, + { + values: ["Property Value Updated"], + } + ); + + expect(customerPropertyValue).toBeDefined(); + }); - await deleteCustomerProperty(client, workspaceSlug, customerProperty.id); - console.log("Deleted customer property: ", customerProperty.id); -} + it("should list customer property values", async () => { + const allCustomerPropertyValues = await client.customers.properties.listValues(workspaceSlug, customerId); -// ===== CUSTOMER PROPERTY API METHODS ===== -async function createCustomerProperty(client: PlaneClient, workspaceSlug: string) { - const customerProperty = await client.customers.properties.createPropertyDefinition(workspaceSlug, { - name: `test-customer-property-${new Date().getTime()}`, - display_name: `Test Customer Property ${new Date().getTime()}`, - description: "Test Customer Property Description", - property_type: "TEXT", + expect(allCustomerPropertyValues).toBeDefined(); + expect(Object.keys(allCustomerPropertyValues).length).toBeGreaterThan(0); + expect(Array.isArray(allCustomerPropertyValues[customerProperty.id])).toBe(true); + expect(allCustomerPropertyValues[customerProperty.id].length).toBeGreaterThan(0); }); - return customerProperty; -} - -async function retrieveCustomerProperty(client: PlaneClient, workspaceSlug: string, propertyId: string) { - const customerProperty = await client.customers.properties.retrievePropertyDefinition(workspaceSlug, propertyId); - return customerProperty; -} - -async function updateCustomerProperty(client: PlaneClient, workspaceSlug: string, propertyId: string) { - return await client.customers.properties.updatePropertyDefinition(workspaceSlug, propertyId, { - display_name: `Updated Test Customer Property ${new Date().getTime()}`, - description: "Updated Test Customer Property Description", - }); -} -async function listCustomerProperties(client: PlaneClient, workspaceSlug: string) { - return await client.customers.properties.listPropertyDefinitions(workspaceSlug, { - limit: 10, - offset: 0, - }); -} - -async function deleteCustomerProperty(client: PlaneClient, workspaceSlug: string, propertyId: string) { - return await client.customers.properties.deletePropertyDefinition(workspaceSlug, propertyId); -} - -// ===== CUSTOMER PROPERTY VALUES API METHODS ===== -async function updateCustomerPropertyValue( - client: PlaneClient, - workspaceSlug: string, - customerId: string, - propertyId: string -) { - return await client.customers.properties.updateValue(workspaceSlug, customerId, propertyId, { - values: ["Property Value Updated"], + it("should retrieve a customer property value", async () => { + const retrievedCustomerPropertyValue = await client.customers.properties.retrieveValue( + workspaceSlug, + customerId, + customerProperty.id! + ); + + expect(retrievedCustomerPropertyValue).toBeDefined(); }); -} - -async function listCustomerPropertyValues(client: PlaneClient, workspaceSlug: string, customerId: string) { - return await client.customers.properties.listValues(workspaceSlug, customerId); -} - -async function retrieveCustomerPropertyValue( - client: PlaneClient, - workspaceSlug: string, - customerId: string, - propertyId: string -) { - return await client.customers.properties.retrieveValue(workspaceSlug, customerId, propertyId); -} - -if (require.main === module) { - testCustomersPropertiesOptionsAndValues().catch(console.error); -} +}); diff --git a/tests/unit/customers/requests.test.ts b/tests/unit/customers/requests.test.ts index 290d84f..7596eb0 100644 --- a/tests/unit/customers/requests.test.ts +++ b/tests/unit/customers/requests.test.ts @@ -1,81 +1,79 @@ import { PlaneClient } from "../../../src/client/plane-client"; +import { CustomerRequest } from "../../../src/models/Customer"; import { config } from "../constants"; -import { createTestClient } from "../../helpers/test-utils"; +import { createTestClient, randomizeName } from "../../helpers/test-utils"; +import { describeIf as describe } from "../../helpers/conditional-tests"; -export async function testCustomersRequests() { - const client = createTestClient(); +describe(!!(config.workspaceSlug && config.customerId), "Customer Requests API Tests", () => { + let client: PlaneClient; + let workspaceSlug: string; + let customerId: string; + let customerRequest: CustomerRequest; - const workspaceSlug = config.workspaceSlug; - const customerId = config.customerId; - - if (!workspaceSlug || !customerId) { - console.error("workspaceSlug and customerId are required"); - return; - } - - const customerRequest = await createCustomerRequest(client, workspaceSlug, customerId); - console.log("Created customer request: ", customerRequest); + beforeAll(async () => { + client = createTestClient(); + workspaceSlug = config.workspaceSlug; + customerId = config.customerId; + }); - const retrievedCustomerRequest = await retrieveCustomerRequest(client, workspaceSlug, customerId, customerRequest.id); - console.log("Retrieved customer request: ", retrievedCustomerRequest); + afterAll(async () => { + // Clean up created customer request + if (customerRequest?.id) { + try { + await client.customers.requests.delete(workspaceSlug, customerId, customerRequest.id); + } catch (error) { + console.warn("Failed to delete customer request:", error); + } + } + }); - const updatedCustomerRequest = await updateCustomerRequest(client, workspaceSlug, customerId, customerRequest.id); - console.log("Updated customer request: ", updatedCustomerRequest); + it("should create a customer request", async () => { + customerRequest = await client.customers.requests.create(workspaceSlug, customerId, { + name: randomizeName("Test Customer Request"), + description: "Test Customer Request Description", + }); - const customerRequests = await listCustomerRequests(client, workspaceSlug, customerId); - console.log("Listed customer requests: ", customerRequests); + expect(customerRequest).toBeDefined(); + expect(customerRequest.id).toBeDefined(); + expect(customerRequest.name).toContain("Test Customer Request"); + expect(customerRequest.description).toBe("Test Customer Request Description"); + }); - await deleteCustomerRequest(client, workspaceSlug, customerId, customerRequest.id); - console.log("Deleted customer request: ", customerRequest.id); -} + it("should retrieve a customer request", async () => { + const retrievedCustomerRequest = await client.customers.requests.retrieve( + workspaceSlug, + customerId, + customerRequest.id! + ); -async function createCustomerRequest(client: PlaneClient, workspaceSlug: string, customerId: string) { - const customerRequest = await client.customers.requests.create(workspaceSlug, customerId, { - name: `Test Customer Request ${new Date().getTime()}`, - description: "Test Customer Request Description", + expect(retrievedCustomerRequest).toBeDefined(); + expect(retrievedCustomerRequest.id).toBe(customerRequest.id); + expect(retrievedCustomerRequest.name).toBe(customerRequest.name); }); - return customerRequest; -} -async function retrieveCustomerRequest( - client: PlaneClient, - workspaceSlug: string, - customerId: string, - requestId: string -) { - const customerRequest = await client.customers.requests.retrieve(workspaceSlug, customerId, requestId); - return customerRequest; -} + it("should update a customer request", async () => { + const updatedCustomerRequest = await client.customers.requests.update( + workspaceSlug, + customerId, + customerRequest.id!, + { + name: randomizeName("Updated Test Customer Request"), + description: "Updated Test Customer Request Description", + } + ); -async function updateCustomerRequest( - client: PlaneClient, - workspaceSlug: string, - customerId: string, - requestId: string -) { - return await client.customers.requests.update(workspaceSlug, customerId, requestId, { - name: `Updated Test Customer Request ${new Date().getTime()}`, - description: "Updated Test Customer Request Description", + expect(updatedCustomerRequest).toBeDefined(); + expect(updatedCustomerRequest.id).toBe(customerRequest.id); + expect(updatedCustomerRequest.name).toContain("Updated Test Customer Request"); + expect(updatedCustomerRequest.description).toBe("Updated Test Customer Request Description"); }); -} -async function listCustomerRequests(client: PlaneClient, workspaceSlug: string, customerId: string) { - const customerRequests = await client.customers.requests.list(workspaceSlug, customerId, { - limit: 10, - offset: 0, - }); - return customerRequests; -} + it("should list customer requests", async () => { + const customerRequests = await client.customers.requests.list(workspaceSlug, customerId); -async function deleteCustomerRequest( - client: PlaneClient, - workspaceSlug: string, - customerId: string, - requestId: string -) { - await client.customers.requests.delete(workspaceSlug, customerId, requestId); -} + expect(customerRequests.results.length).toBeGreaterThan(0); -if (require.main === module) { - testCustomersRequests().catch(console.error); -} + const foundRequest = customerRequests.results.find((r) => r.id === customerRequest.id); + expect(foundRequest).toBeDefined(); + }); +}); diff --git a/tests/unit/customers/work-items.test.ts b/tests/unit/customers/work-items.test.ts index 5bb89d6..c995ec0 100644 --- a/tests/unit/customers/work-items.test.ts +++ b/tests/unit/customers/work-items.test.ts @@ -1,53 +1,38 @@ import { PlaneClient } from "../../../src/client/plane-client"; import { config } from "../constants"; import { createTestClient } from "../../helpers/test-utils"; +import { describeIf as describe } from "../../helpers/conditional-tests"; -export async function testCustomersWorkItems() { - const client = createTestClient(); - - const workspaceSlug = config.workspaceSlug; - const customerId = config.customerId; - const workItemId = config.workItemId; - - if (!workspaceSlug || !customerId || !workItemId) { - console.error("workspaceSlug, customerId and workItemId are required"); - return; - } - - const customer = await linkWorkItemsToCustomer(client, workspaceSlug, customerId, [workItemId]); - console.log("Linked work items to customer: ", customer); - - const retrievedCustomerWorkItems = await listCustomerWorkItems(client, workspaceSlug, customerId); - console.log("Retrieved customer work items: ", retrievedCustomerWorkItems); - - const updatedCustomer = await unlinkWorkItemFromCustomer(client, workspaceSlug, customerId, workItemId); - console.log("Unlinked work item from customer: ", updatedCustomer); -} - -async function linkWorkItemsToCustomer( - client: PlaneClient, - workspaceSlug: string, - customerId: string, - issueIds: string[] -) { - const customer = await client.customers.linkIssuesToCustomer(workspaceSlug, customerId, issueIds); - return customer; -} - -async function listCustomerWorkItems(client: PlaneClient, workspaceSlug: string, customerId: string) { - const customer = await client.customers.listCustomerIssues(workspaceSlug, customerId); - return customer; -} - -async function unlinkWorkItemFromCustomer( - client: PlaneClient, - workspaceSlug: string, - customerId: string, - issueId: string -) { - return await client.customers.unlinkIssueFromCustomer(workspaceSlug, customerId, issueId); -} - -if (require.main === module) { - testCustomersWorkItems().catch(console.error); -} +describe(!!(config.workspaceSlug && config.customerId && config.workItemId), "Customer Work Items API Tests", () => { + let client: PlaneClient; + let workspaceSlug: string; + let customerId: string; + let workItemId: string; + + beforeAll(async () => { + client = createTestClient(); + workspaceSlug = config.workspaceSlug; + customerId = config.customerId; + workItemId = config.workItemId; + }); + + it("should link work items to customer", async () => { + const linkedIssues = await client.customers.linkIssuesToCustomer(workspaceSlug, customerId, [workItemId]); + + expect(linkedIssues).toBeDefined(); + expect(linkedIssues.linked_issues.length).toBe(1); + }); + + it("should list customer work items", async () => { + const customerWorkItems = await client.customers.listCustomerIssues(workspaceSlug, customerId); + + expect(customerWorkItems.length).toBeGreaterThan(0); + + const foundWorkItem = customerWorkItems.find((wi) => wi.id === workItemId); + expect(foundWorkItem).toBeDefined(); + }); + + it("should unlink work item from customer", async () => { + await client.customers.unlinkIssueFromCustomer(workspaceSlug, customerId, workItemId); + }); +}); diff --git a/tests/unit/cycle.test.ts b/tests/unit/cycle.test.ts index 678f548..b75d495 100644 --- a/tests/unit/cycle.test.ts +++ b/tests/unit/cycle.test.ts @@ -1,197 +1,182 @@ import { PlaneClient } from "../../src/client/plane-client"; -import { UpdateCycleRequest } from "../../src/models/Cycle"; +import { UpdateCycleRequest, Cycle, WorkItem } from "../../src/models"; import { config } from "./constants"; import { createTestClient } from "../helpers/test-utils"; +import { describeIf as describe } from "../helpers/conditional-tests"; + +describe(!!(config.workspaceSlug && config.projectId && config.workItemId), "Cycle API Tests", () => { + let client: PlaneClient; + let workspaceSlug: string; + let projectId: string; + let workItemId: string; + let userId: string; + let cycle: Cycle; + let cycle2: Cycle; + let workItem2: WorkItem; + + beforeAll(async () => { + client = createTestClient(); + workspaceSlug = config.workspaceSlug; + projectId = config.projectId; + workItemId = config.workItemId; + + // Get current user for cycle ownership + const me = await client.users.me(); + userId = me.id!; + + // Ensure project has cycle view enabled + const project = await client.projects.retrieve(workspaceSlug, projectId); + if (!project.cycle_view) { + await client.projects.update(workspaceSlug, projectId, { + cycle_view: true, + }); + } + }); -export async function testCycles() { - const client = createTestClient(); - - const workspaceSlug = config.workspaceSlug; - const projectId = config.projectId; - const workItemId = config.workItemId; - - if (!workspaceSlug || !projectId || !workItemId) { - console.error("workspaceSlug, projectId and workItemId are required"); - return; - } + afterAll(async () => { + // Clean up created resources + if (cycle?.id) { + try { + await client.cycles.delete(workspaceSlug, projectId, cycle.id); + } catch (error) { + console.warn("Failed to delete cycle:", error); + } + } + if (cycle2?.id) { + try { + await client.cycles.delete(workspaceSlug, projectId, cycle2.id); + } catch (error) { + console.warn("Failed to delete cycle2:", error); + } + } + if (workItem2?.id) { + try { + await client.workItems.delete(workspaceSlug, projectId, workItem2.id); + } catch (error) { + console.warn("Failed to delete workItem2:", error); + } + } + }); - const project = await client.projects.retrieve(workspaceSlug, projectId); - if (!project.cycle_view) { - await client.projects.update(workspaceSlug, projectId, { - cycle_view: true, + it("should create a cycle", async () => { + cycle = await client.cycles.create(workspaceSlug, projectId, { + name: "Test Cycle", + description: "Test Cycle Description", + owned_by: userId, + project_id: projectId, }); - } - const cycle = await createCycle(client, workspaceSlug, projectId); - console.log("Created cycle: ", cycle); - await new Promise((resolve) => setTimeout(resolve, 1000)); + expect(cycle).toBeDefined(); + expect(cycle.id).toBeDefined(); + expect(cycle.name).toBe("Test Cycle"); + expect(cycle.description).toBe("Test Cycle Description"); + expect(cycle.owned_by).toBe(userId); + expect(cycle.project).toBe(projectId); + }); - const retrievedCycle = await retrieveCycle(client, workspaceSlug, projectId, cycle.id); - console.log("Retrieved cycle: ", retrievedCycle); - await new Promise((resolve) => setTimeout(resolve, 1000)); + it("should retrieve a cycle", async () => { + const retrievedCycle = await client.cycles.retrieve(workspaceSlug, projectId, cycle.id); - const updatedCycle = await updateCycle(client, workspaceSlug, projectId, cycle.id, { - name: "Updated Test Cycle", - description: "Updated Test Cycle Description", + expect(retrievedCycle).toBeDefined(); + expect(retrievedCycle.id).toBe(cycle.id); + expect(retrievedCycle.name).toBe(cycle.name); + expect(retrievedCycle.description).toBe(cycle.description); }); - console.log("Updated cycle: ", updatedCycle); - await new Promise((resolve) => setTimeout(resolve, 1000)); - const cycles = await listCycles(client, workspaceSlug, projectId); - console.log("Listed cycles: ", cycles); - await new Promise((resolve) => setTimeout(resolve, 1000)); + it("should update a cycle", async () => { + const updateData: UpdateCycleRequest = { + name: "Updated Test Cycle", + description: "Updated Test Cycle Description", + }; - await addWorkItemsToCycle(client, workspaceSlug, projectId, cycle.id, workItemId); - console.log("Added work item to cycle: ", workItemId); - await new Promise((resolve) => setTimeout(resolve, 1000)); + const updatedCycle = await client.cycles.update(workspaceSlug, projectId, cycle.id, updateData); - const itemsInCycle = await listWorkItemsInCycle(client, workspaceSlug, projectId, cycle.id); - console.log("Listed work items in cycle: ", itemsInCycle); - await new Promise((resolve) => setTimeout(resolve, 1000)); + expect(updatedCycle).toBeDefined(); + expect(updatedCycle.id).toBe(cycle.id); + expect(updatedCycle.name).toBe("Updated Test Cycle"); + expect(updatedCycle.description).toBe("Updated Test Cycle Description"); + }); - const removedItem = await removeWorkItemFromCycle(client, workspaceSlug, projectId, cycle.id, workItemId); - console.log("Removed work item from cycle: ", removedItem); - await new Promise((resolve) => setTimeout(resolve, 1000)); + it("should list cycles", async () => { + const cycles = await client.cycles.list(workspaceSlug, projectId); - // Create a second cycle for transfer testing - const cycle2 = await createCycle(client, workspaceSlug, projectId); - console.log("Created second cycle for transfer: ", cycle2); - await new Promise((resolve) => setTimeout(resolve, 1000)); + expect(cycles).toBeDefined(); + expect(Array.isArray(cycles.results)).toBe(true); + expect(cycles.results.length).toBeGreaterThan(0); - // create a new work item for transfer testing - const workItem2 = await client.workItems.create(workspaceSlug, projectId, { - name: "Test Work Item 2", + const foundCycle = cycles.results.find((c) => c.id === cycle.id); + expect(foundCycle).toBeDefined(); + expect(foundCycle?.name).toBe("Updated Test Cycle"); }); - console.log("Created new work item for transfer: ", workItem2); - await new Promise((resolve) => setTimeout(resolve, 1000)); - - // Add work item back to first cycle for transfer test - await addWorkItemsToCycle(client, workspaceSlug, projectId, cycle.id, workItemId); - console.log("Re-added work item to first cycle: ", workItemId); - await new Promise((resolve) => setTimeout(resolve, 1000)); - - await transferWorkItemsToAnotherCycle(client, workspaceSlug, projectId, cycle.id, cycle2.id); - console.log("Transferred work items to another cycle"); - await new Promise((resolve) => setTimeout(resolve, 1000)); - - // await archiveCycle(client, workspaceSlug, projectId, cycle.id); - // console.log("Archived cycle: ", cycle.id); - // await new Promise((resolve) => setTimeout(resolve, 1000)); - - // const archivedCycles = await listArchivedCycles( - // client, - // workspaceSlug, - // projectId - // ); - // console.log("Listed archived cycles: ", archivedCycles); - // await new Promise((resolve) => setTimeout(resolve, 1000)); - - // await unArchiveCycle(client, workspaceSlug, projectId, cycle.id); - // console.log("Unarchived cycle: ", cycle.id); - // await new Promise((resolve) => setTimeout(resolve, 1000)); - - await deleteCycle(client, workspaceSlug, projectId, cycle.id); - console.log("Deleted cycle: ", cycle.id); - await new Promise((resolve) => setTimeout(resolve, 1000)); - - await deleteCycle(client, workspaceSlug, projectId, cycle2.id); - console.log("Deleted second cycle: ", cycle2.id); -} - -async function createCycle(client: PlaneClient, workspaceSlug: string, projectId: string) { - return await client.cycles.create(workspaceSlug, projectId, { - name: "Test Cycle", - description: "Test Cycle Description", - owned_by: config.userId, - project_id: projectId, + + it("should add work items to cycle", async () => { + await client.cycles.addWorkItemsToCycle(workspaceSlug, projectId, cycle.id, [workItemId]); + + const itemsInCycle = await client.cycles.listWorkItemsInCycle(workspaceSlug, projectId, cycle.id); + + expect(itemsInCycle).toBeDefined(); + expect(Array.isArray(itemsInCycle.results)).toBe(true); + expect(itemsInCycle.results.length).toBeGreaterThan(0); + + const foundWorkItem = itemsInCycle.results.find((item) => item.id === workItemId); + expect(foundWorkItem).toBeDefined(); }); -} - -async function retrieveCycle(client: PlaneClient, workspaceSlug: string, projectId: string, cycleId: string) { - return await client.cycles.retrieve(workspaceSlug, projectId, cycleId); -} - -async function updateCycle( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - cycleId: string, - cycle: UpdateCycleRequest -) { - return await client.cycles.update(workspaceSlug, projectId, cycleId, cycle); -} - -async function listCycles(client: PlaneClient, workspaceSlug: string, projectId: string) { - return await client.cycles.list(workspaceSlug, projectId); -} - -async function deleteCycle(client: PlaneClient, workspaceSlug: string, projectId: string, cycleId: string) { - return await client.cycles.delete(workspaceSlug, projectId, cycleId); -} - -async function addWorkItemsToCycle( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - cycleId: string, - workItemId: string -) { - return await client.cycles.addWorkItemsToCycle(workspaceSlug, projectId, cycleId, [workItemId]); -} - -async function listWorkItemsInCycle(client: PlaneClient, workspaceSlug: string, projectId: string, cycleId: string) { - return await client.cycles.listWorkItemsInCycle(workspaceSlug, projectId, cycleId); -} - -async function removeWorkItemFromCycle( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - cycleId: string, - workItemId: string -) { - return await client.cycles.removeWorkItemFromCycle(workspaceSlug, projectId, cycleId, workItemId); -} - -async function transferWorkItemsToAnotherCycle( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - cycleId: string, - newCycleId: string -) { - return await client.cycles.transferWorkItemsToAnotherCycle(workspaceSlug, projectId, cycleId, { - new_cycle_id: newCycleId, + + it("should remove work item from cycle", async () => { + await client.cycles.removeWorkItemFromCycle(workspaceSlug, projectId, cycle.id, workItemId); + + const itemsInCycle = await client.cycles.listWorkItemsInCycle(workspaceSlug, projectId, cycle.id); + + expect(itemsInCycle).toBeDefined(); + expect(Array.isArray(itemsInCycle.results)).toBe(true); + + const foundWorkItem = itemsInCycle.results.find((item) => item.id === workItemId); + expect(foundWorkItem).toBeUndefined(); }); -} -async function archiveCycle(client: PlaneClient, workspaceSlug: string, projectId: string, cycleId: string) { - return await client.cycles.archive(workspaceSlug, projectId, cycleId); -} + it("should create a second cycle for transfer testing", async () => { + cycle2 = await client.cycles.create(workspaceSlug, projectId, { + name: "Test Cycle 2", + description: "Test Cycle 2 Description", + owned_by: userId, + project_id: projectId, + }); + + expect(cycle2).toBeDefined(); + expect(cycle2.id).toBeDefined(); + expect(cycle2.name).toBe("Test Cycle 2"); + expect(cycle2.id).not.toBe(cycle.id); + }); -async function listArchivedCycles(client: PlaneClient, workspaceSlug: string, projectId: string) { - return await client.cycles.listArchived(workspaceSlug, projectId); -} + it("should create a new work item for transfer testing", async () => { + workItem2 = await client.workItems.create(workspaceSlug, projectId, { + name: "Test Work Item 2", + }); -async function unArchiveCycle(client: PlaneClient, workspaceSlug: string, projectId: string, cycleId: string) { - return await client.cycles.unArchive(workspaceSlug, projectId, cycleId); -} + expect(workItem2).toBeDefined(); + expect(workItem2.id).toBeDefined(); + expect(workItem2.name).toBe("Test Work Item 2"); + }); -async function justArchiveCycle() { - const client = createTestClient(); - const workspaceSlug = config.workspaceSlug; - const projectId = config.projectId; + it("should transfer work items to another cycle", async () => { + // Add work item back to first cycle for transfer test + await client.cycles.addWorkItemsToCycle(workspaceSlug, projectId, cycle.id, [workItemId]); - const project = await client.projects.retrieve(workspaceSlug, projectId); - if (!project.cycle_view) { - await client.projects.update(workspaceSlug, projectId, { - cycle_view: true, + // Transfer work items from first cycle to second cycle + await client.cycles.transferWorkItemsToAnotherCycle(workspaceSlug, projectId, cycle.id, { + new_cycle_id: cycle2.id, }); - } - return await client.cycles.archive(workspaceSlug, projectId, "e1ca5ee2-c968-4be5-80fa-f6dff66bea98"); -} + // Verify work item is now in second cycle + const itemsInCycle2 = await client.cycles.listWorkItemsInCycle(workspaceSlug, projectId, cycle2.id); + expect(itemsInCycle2.results.length).toBeGreaterThan(0); -if (require.main === module) { - testCycles().catch(console.error); -} + const foundWorkItem = itemsInCycle2.results.find((item) => item.id === workItemId); + expect(foundWorkItem).toBeDefined(); + + // Verify work item is no longer in first cycle + const itemsInCycle1 = await client.cycles.listWorkItemsInCycle(workspaceSlug, projectId, cycle.id); + const foundWorkItemInCycle1 = itemsInCycle1.results.find((item) => item.id === workItemId); + expect(foundWorkItemInCycle1).toBeUndefined(); + }); +}); diff --git a/tests/unit/epic.test.ts b/tests/unit/epic.test.ts index 58979c2..e3b709e 100644 --- a/tests/unit/epic.test.ts +++ b/tests/unit/epic.test.ts @@ -1,29 +1,30 @@ -import { PlaneClient } from "../../src/client/plane-client"; import { config } from "./constants"; +import { PlaneClient } from "../../src/client/plane-client"; import { createTestClient } from "../helpers/test-utils"; - -export async function testEpics() { - const client = createTestClient(); - - const workspaceSlug = config.workspaceSlug; - const projectId = config.projectId; - - if (!workspaceSlug || !projectId) { - console.error("workspaceSlug and projectId are required"); - return; - } - - const project = await client.projects.retrieve(workspaceSlug, projectId); - - const epics = await client.epics.list(workspaceSlug, projectId); - - console.log("Listed epics: ", epics); - - const epic = await client.epics.retrieve(workspaceSlug, projectId, epics.results[0]!.id!); - - console.log("Retrieved epic: ", epic); -} - -if (require.main === module) { - testEpics().catch(console.error); -} +import { describeIf as describe } from "../helpers/conditional-tests"; + +describe(!!(config.workspaceSlug && config.projectId), "Epic API Tests", () => { + let client: PlaneClient; + let workspaceSlug: string; + let projectId: string; + + beforeAll(async () => { + client = createTestClient(); + workspaceSlug = config.workspaceSlug; + projectId = config.projectId; + }); + + it("should list epics", async () => { + const epics = await client.epics.list(workspaceSlug, projectId); + expect(epics).toBeDefined(); + expect(epics.results.length).toBeGreaterThan(0); + }); + + it("should retrieve an epic", async () => { + const epics = await client.epics.list(workspaceSlug, projectId); + const epic = await client.epics.retrieve(workspaceSlug, projectId, epics.results[0]!.id!); + expect(epic).toBeDefined(); + expect(epic.id).toBe(epics.results[0]!.id); + expect(epic.name).toBe(epics.results[0]!.name); + }); +}); diff --git a/tests/unit/intake.test.ts b/tests/unit/intake.test.ts index db04bdf..8e0d146 100644 --- a/tests/unit/intake.test.ts +++ b/tests/unit/intake.test.ts @@ -1,95 +1,78 @@ import { PlaneClient } from "../../src/client/plane-client"; -import { PaginatedResponse } from "../../src/models/common"; import { IntakeWorkItem } from "../../src/models/Intake"; import { config } from "./constants"; -import { createTestClient } from "../helpers/test-utils"; +import { createTestClient, randomizeName } from "../helpers/test-utils"; +import { describeIf as describe } from "../helpers/conditional-tests"; -export async function testIntake() { - const client = createTestClient(); +describe(!!(config.workspaceSlug && config.projectId), "Intake API Tests", () => { + let client: PlaneClient; + let workspaceSlug: string; + let projectId: string; + let intakeWorkItem: IntakeWorkItem; - const workspaceSlug = config.workspaceSlug; - const projectId = config.projectId; + beforeAll(async () => { + client = createTestClient(); + workspaceSlug = config.workspaceSlug; + projectId = config.projectId; - if (!workspaceSlug || !projectId) { - console.error("workspaceSlug and projectId are required"); - return; - } + // Enable intake view if not already enabled + await client.projects.update(workspaceSlug, projectId, { + intake_view: true, + }); + }); - // enable intake if didn't already - const updatedProject = await client.projects.update(workspaceSlug, projectId, { - intake_view: true, + afterAll(async () => { + // Clean up created intake work item + if (intakeWorkItem?.issue) { + try { + await client.intake.delete(workspaceSlug, projectId, intakeWorkItem.issue); + } catch (error) { + console.warn("Failed to delete intake work item:", error); + } + } }); - const intakeWorkItem = await createIntake(client, workspaceSlug, projectId); - console.log("Created intake: ", intakeWorkItem); + it("should create an intake work item", async () => { + intakeWorkItem = await client.intake.create(workspaceSlug, projectId, { + issue: { + name: randomizeName("Test Intake"), + description_html: "

Test Intake Description

", + }, + }); - const retrievedIntake = await retrieveIntake(client, workspaceSlug, projectId, intakeWorkItem.issue!); - console.log("Retrieved intake: ", retrievedIntake); + expect(intakeWorkItem).toBeDefined(); + expect(intakeWorkItem.id).toBeDefined(); + expect(intakeWorkItem.issue).toBeDefined(); + }); - const updatedIntake = await updateIntake(client, workspaceSlug, projectId, intakeWorkItem.issue!, intakeWorkItem); - console.log("Updated intake: ", updatedIntake); + it("should retrieve an intake work item", async () => { + const retrievedIntake = await client.intake.retrieve(workspaceSlug, projectId, intakeWorkItem.issue!); - const intakes = await listIntake(client, workspaceSlug, projectId); - console.log("Listed intakes: ", intakes); + expect(retrievedIntake).toBeDefined(); + expect(retrievedIntake.id).toBe(intakeWorkItem.id); + expect(retrievedIntake.issue).toBe(intakeWorkItem.issue); + }); - await deleteIntake(client, workspaceSlug, projectId, intakeWorkItem.issue!); - console.log("Intake deleted: ", intakeWorkItem.id); -} + it("should update an intake work item", async () => { + const updatedIntake = await client.intake.update(workspaceSlug, projectId, intakeWorkItem.issue!, { + issue: { + name: "Updated Test Intake", + description_html: "

Updated Test Intake Description

", + }, + }); -async function createIntake(client: PlaneClient, workspaceSlug: string, projectId: string): Promise { - const intake = await client.intake.create(workspaceSlug, projectId, { - issue: { - name: "Test Intake", - description_html: "

Test Intake Description

", - }, + expect(updatedIntake).toBeDefined(); + expect(updatedIntake.id).toBe(intakeWorkItem.id); }); - return intake; -} -async function retrieveIntake( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - intakeWorkItemId: string -): Promise { - const intake = await client.intake.retrieve(workspaceSlug, projectId, intakeWorkItemId); - return intake; -} + it("should list intake work items", async () => { + const intakes = await client.intake.list(workspaceSlug, projectId); -async function listIntake( - client: PlaneClient, - workspaceSlug: string, - projectId: string -): Promise> { - const intakes = await client.intake.list(workspaceSlug, projectId); - return intakes; -} + expect(intakes).toBeDefined(); + expect(Array.isArray(intakes.results)).toBe(true); + expect(intakes.results.length).toBeGreaterThan(0); -async function updateIntake( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - intakeWorkItemId: string, - intake: IntakeWorkItem -): Promise { - const updatedIntake = await client.intake.update(workspaceSlug, projectId, intakeWorkItemId, { - issue: { - name: "Updated Test Intake", - description_html: "

Updated Test Intake Description

", - }, + const foundIntake = intakes.results.find((i) => i.id === intakeWorkItem.id); + expect(foundIntake).toBeDefined(); }); - return updatedIntake; -} - -async function deleteIntake( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - intakeWorkItemId: string -): Promise { - await client.intake.delete(workspaceSlug, projectId, intakeWorkItemId); -} - -if (require.main === module) { - testIntake().catch(console.error); -} +}); diff --git a/tests/unit/label.test.ts b/tests/unit/label.test.ts index 4e7a9d1..d68d664 100644 --- a/tests/unit/label.test.ts +++ b/tests/unit/label.test.ts @@ -1,70 +1,72 @@ import { PlaneClient } from "../../src/client/plane-client"; import { Label } from "../../src/models/Label"; import { config } from "./constants"; -import { createTestClient } from "../helpers/test-utils"; +import { createTestClient, randomizeName } from "../helpers/test-utils"; +import { describeIf as describe } from "../helpers/conditional-tests"; -export async function testLabels() { - const client = createTestClient(); +describe(!!(config.workspaceSlug && config.projectId), "Label API Tests", () => { + let client: PlaneClient; + let workspaceSlug: string; + let projectId: string; + let label: Label; - const workspaceSlug = config.workspaceSlug; - const projectId = config.projectId; - - if (!workspaceSlug || !projectId) { - console.error("workspaceSlug and projectId are required"); - return; - } - - const labelObj = await createLabel(client, workspaceSlug, projectId); - console.log("Created label: ", labelObj); + beforeAll(async () => { + client = createTestClient(); + workspaceSlug = config.workspaceSlug; + projectId = config.projectId; + }); - const retrievedLabel = await retrieveLabel(client, workspaceSlug, projectId, labelObj.id); - console.log("Retrieved label: ", retrievedLabel); + afterAll(async () => { + // Clean up created label + if (label?.id) { + try { + await client.labels.delete(workspaceSlug, projectId, label.id); + } catch (error) { + console.warn("Failed to delete label:", error); + } + } + }); - const updatedLabel = await updateLabel(client, workspaceSlug, projectId, labelObj.id, labelObj); - console.log("Updated label: ", updatedLabel); + it("should create a label", async () => { + label = await client.labels.create(workspaceSlug, projectId, { + name: randomizeName("Test Label"), + description: "Test Label Description", + }); - const labels = await listLabels(client, workspaceSlug, projectId); - console.log("Listed labels: ", labels); + expect(label).toBeDefined(); + expect(label.id).toBeDefined(); + expect(label.name).toContain("Test Label"); + expect(label.description).toBe("Test Label Description"); + }); - await deleteLabel(client, workspaceSlug, projectId, labelObj.id); - console.log("Label deleted: ", labelObj.id); -} + it("should retrieve a label", async () => { + const retrievedLabel = await client.labels.retrieve(workspaceSlug, projectId, label.id!); -async function createLabel(client: PlaneClient, workspaceSlug: string, projectId: string) { - const label = await client.labels.create(workspaceSlug, projectId, { - name: "Test Label " + new Date().getTime(), - description: "Test Label Description", + expect(retrievedLabel).toBeDefined(); + expect(retrievedLabel.id).toBe(label.id); + expect(retrievedLabel.name).toBe(label.name); + expect(retrievedLabel.description).toBe(label.description); }); - return label; -} -async function retrieveLabel(client: PlaneClient, workspaceSlug: string, projectId: string, labelId: string) { - const label = await client.labels.retrieve(workspaceSlug, projectId, labelId); - return label; -} + it("should update a label", async () => { + const updatedLabel = await client.labels.update(workspaceSlug, projectId, label.id!, { + description: "Updated Test Label Description", + }); -async function updateLabel( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - labelId: string, - label: Label -) { - const updatedLabel = await client.labels.update(workspaceSlug, projectId, labelId, { - description: "Updated Test Label Description" + new Date().toISOString(), + expect(updatedLabel).toBeDefined(); + expect(updatedLabel.id).toBe(label.id); + expect(updatedLabel.description).toBe("Updated Test Label Description"); }); - return updatedLabel; -} -async function deleteLabel(client: PlaneClient, workspaceSlug: string, projectId: string, labelId: string) { - await client.labels.delete(workspaceSlug, projectId, labelId); -} + it("should list labels", async () => { + const labels = await client.labels.list(workspaceSlug, projectId); -async function listLabels(client: PlaneClient, workspaceSlug: string, projectId: string) { - const labels = await client.labels.list(workspaceSlug, projectId); - return labels; -} + expect(labels).toBeDefined(); + expect(Array.isArray(labels.results)).toBe(true); + expect(labels.results.length).toBeGreaterThan(0); -if (require.main === module) { - testLabels().catch(console.error); -} + const foundLabel = labels.results.find((l) => l.id === label.id); + expect(foundLabel).toBeDefined(); + expect(foundLabel?.description).toBe("Updated Test Label Description"); + }); +}); diff --git a/tests/unit/module.test.ts b/tests/unit/module.test.ts index f0e13b9..884a3ce 100644 --- a/tests/unit/module.test.ts +++ b/tests/unit/module.test.ts @@ -1,104 +1,99 @@ import { PlaneClient } from "../../src/client/plane-client"; -import { UpdateModuleRequest } from "../../src/models/Module"; +import { Module } from "../../src/models/Module"; import { config } from "./constants"; -import { createTestClient } from "../helpers/test-utils"; +import { createTestClient, randomizeName } from "../helpers/test-utils"; +import { describeIf as describe } from "../helpers/conditional-tests"; + +describe(!!(config.workspaceSlug && config.projectId && config.workItemId), "Module API Tests", () => { + let client: PlaneClient; + let workspaceSlug: string; + let projectId: string; + let workItemId: string; + let module: Module; + + beforeAll(async () => { + client = createTestClient(); + workspaceSlug = config.workspaceSlug; + projectId = config.projectId; + workItemId = config.workItemId; + }); -export async function testModules() { - const client = createTestClient(); + afterAll(async () => { + // Clean up created module + if (module?.id) { + try { + await client.modules.delete(workspaceSlug, projectId, module.id); + } catch (error) { + console.warn("Failed to delete module:", error); + } + } + }); - const workspaceSlug = config.workspaceSlug; - const projectId = config.projectId; - const workItemId = config.workItemId; + it("should create a module", async () => { + module = await client.modules.create(workspaceSlug, projectId, { + name: randomizeName("Test Module"), + description: "Test Description", + }); - if (!workspaceSlug || !projectId || !workItemId) { - console.error("workspaceSlug, projectId and workItemId are required"); - return; - } + expect(module).toBeDefined(); + expect(module.id).toBeDefined(); + expect(module.name).toContain("Test Module"); + expect(module.description).toBe("Test Description"); + }); - const module = await createModule(client, workspaceSlug, projectId); - console.log("Created module: ", module); - await new Promise((resolve) => setTimeout(resolve, 1000)); + it("should retrieve a module", async () => { + const retrievedModule = await client.modules.retrieve(workspaceSlug, projectId, module.id!); - const retrievedModule = await retrieveModule(client, workspaceSlug, projectId, module.id); - console.log("Retrieved module: ", retrievedModule); - await new Promise((resolve) => setTimeout(resolve, 1000)); + expect(retrievedModule).toBeDefined(); + expect(retrievedModule.id).toBe(module.id); + expect(retrievedModule.name).toBe(module.name); + expect(retrievedModule.description).toBe(module.description); + }); + + it("should update a module", async () => { + const updatedModule = await client.modules.update(workspaceSlug, projectId, module.id!, { + description: "Updated Test Description", + }); + + expect(updatedModule).toBeDefined(); + expect(updatedModule.id).toBe(module.id); + expect(updatedModule.description).toBe("Updated Test Description"); + }); - const updatedModule = await updateModule(client, workspaceSlug, projectId, module.id, module); - console.log("Updated module: ", updatedModule); - await new Promise((resolve) => setTimeout(resolve, 1000)); + it("should list modules", async () => { + const modules = await client.modules.list(workspaceSlug, projectId); - const modules = await listModules(client, workspaceSlug, projectId); - console.log("Listed modules: ", modules); - await new Promise((resolve) => setTimeout(resolve, 1000)); + expect(modules).toBeDefined(); + expect(Array.isArray(modules.results)).toBe(true); + expect(modules.results.length).toBeGreaterThan(0); - await addWorkItemToModule(client, workspaceSlug, projectId, module.id, workItemId); - console.log("Added work item to module: ", workItemId); - await new Promise((resolve) => setTimeout(resolve, 1000)); + const foundModule = modules.results.find((m) => m.id === module.id); + expect(foundModule).toBeDefined(); + expect(foundModule?.description).toBe("Updated Test Description"); + }); + + it("should add work items to module", async () => { + await client.modules.addWorkItemsToModule(workspaceSlug, projectId, module.id!, [workItemId]); + + const itemsInModule = await client.modules.listWorkItemsInModule(workspaceSlug, projectId, module.id!); + + expect(itemsInModule).toBeDefined(); + expect(Array.isArray(itemsInModule.results)).toBe(true); + expect(itemsInModule.results.length).toBeGreaterThan(0); + + const foundWorkItem = itemsInModule.results.find((item) => item.id === workItemId); + expect(foundWorkItem).toBeDefined(); + }); - const itemsInModule = await listWorkItemsInModule(client, workspaceSlug, projectId, module.id); - console.log("Listed work items in module: ", itemsInModule); - await new Promise((resolve) => setTimeout(resolve, 1000)); + it("should remove work item from module", async () => { + await client.modules.removeWorkItemFromModule(workspaceSlug, projectId, module.id!, workItemId); - const removedItem = await removeWorkItemFromModule(client, workspaceSlug, projectId, module.id, workItemId); - console.log("Removed work item from module: ", removedItem); - await new Promise((resolve) => setTimeout(resolve, 1000)); + const itemsInModule = await client.modules.listWorkItemsInModule(workspaceSlug, projectId, module.id!); - await deleteModule(client, workspaceSlug, projectId, module.id); - console.log("Deleted module: ", module.id); -} + expect(itemsInModule).toBeDefined(); + expect(Array.isArray(itemsInModule.results)).toBe(true); -async function createModule(client: PlaneClient, workspaceSlug: string, projectId: string) { - return await client.modules.create(workspaceSlug, projectId, { - name: "Test Module", - description: "Test Description", + const foundWorkItem = itemsInModule.results.find((item) => item.id === workItemId); + expect(foundWorkItem).toBeUndefined(); }); -} - -async function retrieveModule(client: PlaneClient, workspaceSlug: string, projectId: string, moduleId: string) { - return await client.modules.retrieve(workspaceSlug, projectId, moduleId); -} - -async function updateModule( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - moduleId: string, - module: UpdateModuleRequest -) { - return await client.modules.update(workspaceSlug, projectId, moduleId, module); -} - -async function listModules(client: PlaneClient, workspaceSlug: string, projectId: string) { - return await client.modules.list(workspaceSlug, projectId); -} - -async function deleteModule(client: PlaneClient, workspaceSlug: string, projectId: string, moduleId: string) { - return await client.modules.delete(workspaceSlug, projectId, moduleId); -} - -async function addWorkItemToModule( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - moduleId: string, - workItemId: string -) { - return await client.modules.addWorkItemsToModule(workspaceSlug, projectId, moduleId, [workItemId]); -} -async function listWorkItemsInModule(client: PlaneClient, workspaceSlug: string, projectId: string, moduleId: string) { - return await client.modules.listWorkItemsInModule(workspaceSlug, projectId, moduleId); -} - -async function removeWorkItemFromModule( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - moduleId: string, - workItemId: string -) { - return await client.modules.removeWorkItemFromModule(workspaceSlug, projectId, moduleId, workItemId); -} - -if (require.main === module) { - testModules(); -} +}); diff --git a/tests/unit/oauth.test.ts b/tests/unit/oauth.test.ts index d4b5524..5d6ae47 100644 --- a/tests/unit/oauth.test.ts +++ b/tests/unit/oauth.test.ts @@ -1,56 +1,59 @@ -import { PlaneClient } from "../../src/client/plane-client"; import { OAuthClient } from "../../src/client/oauth-client"; -import { Configuration } from "../../src/Configuration"; - -/** - * Test OAuth functionality with both standalone and integrated approaches - */ -export async function testOAuth() { - console.log("🧪 Testing OAuth functionality..."); - - try { - // Test 1: Standalone OAuth Client (for app development) - console.log(" 📋 Testing standalone OAuth client..."); - - if ( - !process.env.PLANE_BASE_URL || - !process.env.PLANE_CLIENT_ID || - !process.env.PLANE_CLIENT_SECRET || - !process.env.PLANE_REDIRECT_URI || - !process.env.PLANE_APP_INSTALLATION_ID - ) { - console.error("❌ Skipping oauth tests, missing environment variables"); - return; - } - - const oauthClient = new OAuthClient({ - baseUrl: process.env.PLANE_BASE_URL, - clientId: process.env.PLANE_CLIENT_ID!, - clientSecret: process.env.PLANE_CLIENT_SECRET!, - redirectUri: process.env.PLANE_REDIRECT_URI!, +import { describeIf as describe } from "../helpers/conditional-tests"; + +const hasOAuthEnv = !!( + process.env.PLANE_BASE_URL && + process.env.PLANE_CLIENT_ID && + process.env.PLANE_CLIENT_SECRET && + process.env.PLANE_REDIRECT_URI && + process.env.PLANE_APP_INSTALLATION_ID +); + +describe(hasOAuthEnv, "OAuth API Tests", () => { + let oauthClient: OAuthClient; + let baseUrl: string; + let clientId: string; + let clientSecret: string; + let redirectUri: string; + let appInstallationId: string; + + beforeAll(() => { + baseUrl = process.env.PLANE_BASE_URL!; + clientId = process.env.PLANE_CLIENT_ID!; + clientSecret = process.env.PLANE_CLIENT_SECRET!; + redirectUri = process.env.PLANE_REDIRECT_URI!; + appInstallationId = process.env.PLANE_APP_INSTALLATION_ID!; + + oauthClient = new OAuthClient({ + baseUrl, + clientId, + clientSecret, + redirectUri, }); + }); + it("should generate authorization URL", () => { const authUrl = oauthClient.getAuthorizationUrl(); - console.log(" ✅ Authorization URL generated:", authUrl); - - const botToken = await oauthClient.getBotToken(process.env.PLANE_APP_INSTALLATION_ID!); - console.log(" ✅ Bot token generated:", botToken); + expect(authUrl).toBeDefined(); + expect(typeof authUrl).toBe("string"); + expect(authUrl).toContain(baseUrl); + expect(authUrl).toContain(clientId); + }); - const installations = await oauthClient.getAppInstallations(botToken.access_token); + it("should get bot token", async () => { + const botToken = await oauthClient.getBotToken(appInstallationId); - console.log(" ✅ App installations generated:", installations); + expect(botToken).toBeDefined(); + expect(botToken.access_token).toBeDefined(); + expect(typeof botToken.access_token).toBe("string"); + }); - // Test authorization URL generation - } catch (error) { - console.error("❌ OAuth test failed:", error); - throw error; - } -} + it("should get app installations", async () => { + const botToken = await oauthClient.getBotToken(appInstallationId); + const installations = await oauthClient.getAppInstallations(botToken.access_token); -if (require.main === module) { - testOAuth().catch((error) => { - console.error("❌ OAuth test failed:", error); - process.exit(1); + expect(installations).toBeDefined(); + expect(Array.isArray(installations)).toBe(true); }); -} +}); diff --git a/tests/unit/page.test.ts b/tests/unit/page.test.ts index f3a1220..c8efd8d 100644 --- a/tests/unit/page.test.ts +++ b/tests/unit/page.test.ts @@ -1,77 +1,59 @@ -import fs from "fs"; import { PlaneClient } from "../../src/client/plane-client"; +import { Page } from "../../src/models/Page"; import { config } from "./constants"; -import { createTestClient } from "../helpers/test-utils"; - -export async function testPage() { - const client = createTestClient(); - - const workspaceSlug = config.workspaceSlug; - const projectId = config.projectId; - - if (!workspaceSlug) { - console.error("workspaceSlug is required"); - return; - } - - if (!projectId) { - console.error("projectId is required"); - return; - } - - const page = await createPage(client, workspaceSlug); - console.log("Created page: ", page); - - const retrievedPage = await retrievePage(client, workspaceSlug, page.id); - console.log("Retrieved page: ", retrievedPage); - - const projectPage = await createProjectPage(client, workspaceSlug, projectId); - console.log("Created project page: ", projectPage); +import { createTestClient, randomizeName } from "../helpers/test-utils"; +import { describeIf as describe } from "../helpers/conditional-tests"; + +describe(!!(config.workspaceSlug && config.projectId), "Page API Tests", () => { + let client: PlaneClient; + let workspaceSlug: string; + let projectId: string; + let workspacePage: Page; + let projectPage: Page; + + beforeAll(async () => { + client = createTestClient(); + workspaceSlug = config.workspaceSlug; + projectId = config.projectId; + }); - const retrievedProjectPage = await retrieveProjectPage(client, workspaceSlug, projectId, projectPage.id); - console.log("Retrieved project page: ", retrievedProjectPage); -} + it("should create a workspace page", async () => { + const content = "

Test Page Content

"; + workspacePage = await client.pages.createWorkspacePage(workspaceSlug, { + name: randomizeName("Test Workspace Page"), + description_html: content, + }); -async function createPage(client: PlaneClient, workspaceSlug: string) { - const content = "

Blank Space

"; - return client.pages.createWorkspacePage(workspaceSlug, { - name: "Test Page Crashable 3", - description_html: content, + expect(workspacePage).toBeDefined(); + expect(workspacePage.id).toBeDefined(); + expect(workspacePage.name).toContain("Test Workspace Page"); }); -} -async function retrievePage(client: PlaneClient, workspaceSlug: string, pageId: string) { - return client.pages.retrieveWorkspacePage(workspaceSlug, pageId); -} + it("should retrieve a workspace page", async () => { + const retrievedPage = await client.pages.retrieveWorkspacePage(workspaceSlug, workspacePage.id!); -async function createProjectPage(client: PlaneClient, workspaceSlug: string, projectId: string) { - const content = "

Blank Space

"; - return client.pages.createProjectPage(workspaceSlug, projectId, { - name: "Test Page Crashable 3", - description_html: content, + expect(retrievedPage).toBeDefined(); + expect(retrievedPage.id).toBe(workspacePage.id); + expect(retrievedPage.name).toBe(workspacePage.name); }); -} -async function retrieveProjectPage(client: PlaneClient, workspaceSlug: string, projectId: string, pageId: string) { - return client.pages.retrieveProjectPage(workspaceSlug, projectId, pageId); -} + it("should create a project page", async () => { + const content = "

Test Project Page Content

"; + projectPage = await client.pages.createProjectPage(workspaceSlug, projectId, { + name: randomizeName("Test Project Page"), + description_html: content, + }); -async function testCreatePageFromFile() { - const client = new PlaneClient({ - apiKey: "plane_api_fae8f19b1e884400831413ef3adfb68b", - baseUrl: "https://test-leak.feat.plane.town", - enableLogging: true, + expect(projectPage).toBeDefined(); + expect(projectPage.id).toBeDefined(); + expect(projectPage.name).toContain("Test Project Page"); }); - const file = fs.readFileSync("/Users/prashantsurya/Projects/sdks/plane-node-sdk/CrashablePage.html", "utf8"); + it("should retrieve a project page", async () => { + const retrievedProjectPage = await client.pages.retrieveProjectPage(workspaceSlug, projectId, projectPage.id!); - const page = await client.pages.createWorkspacePage("testt", { - name: "Test Page Crashable 3", - description_html: file, + expect(retrievedProjectPage).toBeDefined(); + expect(retrievedProjectPage.id).toBe(projectPage.id); + expect(retrievedProjectPage.name).toBe(projectPage.name); }); - console.log("Created page: ", page); -} - -if (require.main === module) { - testCreatePageFromFile().catch(console.error); -} +}); diff --git a/tests/unit/project.test.ts b/tests/unit/project.test.ts index 02bd3ee..e029e35 100644 --- a/tests/unit/project.test.ts +++ b/tests/unit/project.test.ts @@ -1,72 +1,83 @@ import { PlaneClient } from "../../src/client/plane-client"; -import { UpdateProject } from "../../src/models/Project"; +import { UpdateProject, Project } from "../../src/models/Project"; import { config } from "./constants"; -import { createTestClient } from "../helpers/test-utils"; +import { createTestClient, randomizeName } from "../helpers/test-utils"; +import { describeIf as describe } from "../helpers/conditional-tests"; -export async function testProjects() { - const client = createTestClient(); +describe(!!config.workspaceSlug, "Project API Tests", () => { + let client: PlaneClient; + let workspaceSlug: string; + let project: Project; - const workspaceSlug = config.workspaceSlug; + beforeAll(async () => { + client = createTestClient(); + workspaceSlug = config.workspaceSlug; + }); - if (!workspaceSlug) { - console.error("workspaceSlug is required"); - return; - } + afterAll(async () => { + // Clean up created project + if (project?.id) { + try { + await client.projects.delete(workspaceSlug, project.id); + } catch (error) { + console.warn("Failed to delete project:", error); + } + } + }); - const project = await createProject(client, workspaceSlug); - console.log("created project", project); + it("should create a project", async () => { + const name = randomizeName(); + project = await client.projects.create(workspaceSlug, { + name: name, + identifier: name.slice(0, 5).toUpperCase(), + description: "Test Project Description", + }); + + expect(project).toBeDefined(); + expect(project.id).toBeDefined(); + expect(project.name).toBe(name); + expect(project.description).toBe("Test Project Description"); + }); - const retrievedProject = await retrieveProject(client, workspaceSlug, project.id); - console.log("retrieved project", retrievedProject); + it("should retrieve a project", async () => { + const retrievedProject = await client.projects.retrieve(workspaceSlug, project.id); - const updatedProject = await updateProject(client, workspaceSlug, project.id, { - name: "Updated Test Project", - description: "Updated Test Project Description", + expect(retrievedProject).toBeDefined(); + expect(retrievedProject.id).toBe(project.id); + expect(retrievedProject.name).toBe(project.name); + expect(retrievedProject.description).toBe(project.description); }); - console.log("updated project", updatedProject); - - const projects = await listProjects(client, workspaceSlug); - console.log("listed projects", projects); - const members = await getMembers(client, workspaceSlug, project.id); - console.log("project members", members); + it("should update a project", async () => { + const updateData: UpdateProject = { + name: "Updated Test Project", + description: "Updated Test Project Description", + }; - await deleteProject(client, workspaceSlug, project.id); - console.log("project deleted", project.id); -} + const updatedProject = await client.projects.update(workspaceSlug, project.id, updateData); -async function createProject(client: PlaneClient, workspaceSlug: string) { - const project = await client.projects.create(workspaceSlug, { - name: "Test Project", - description: "Test Project Description", + expect(updatedProject).toBeDefined(); + expect(updatedProject.id).toBe(project.id); + expect(updatedProject.name).toBe("Updated Test Project"); + expect(updatedProject.description).toBe("Updated Test Project Description"); }); - return project; -} -async function retrieveProject(client: PlaneClient, workspaceSlug: string, projectId: string) { - const project = await client.projects.retrieve(workspaceSlug, projectId); - return project; -} + it("should list projects", async () => { + const projects = await client.projects.list(workspaceSlug); -async function updateProject(client: PlaneClient, workspaceSlug: string, projectId: string, project: UpdateProject) { - const updatedProject = await client.projects.update(workspaceSlug, projectId, project); - return updatedProject; -} + expect(projects).toBeDefined(); + expect(Array.isArray(projects.results)).toBe(true); + expect(projects.results.length).toBeGreaterThan(0); -async function listProjects(client: PlaneClient, workspaceSlug: string) { - const projects = await client.projects.list(workspaceSlug); - return projects; -} - -async function getMembers(client: PlaneClient, workspaceSlug: string, projectId: string) { - const members = await client.projects.getMembers(workspaceSlug, projectId); - return members; -} + const foundProject = projects.results.find((p) => p.id === project.id); + expect(foundProject).toBeDefined(); + expect(foundProject?.name).toBe("Updated Test Project"); + }); -async function deleteProject(client: PlaneClient, workspaceSlug: string, projectId: string) { - await client.projects.delete(workspaceSlug, projectId); -} + it("should get project members", async () => { + const members = await client.projects.getMembers(workspaceSlug, project.id); -if (require.main === module) { - testProjects().catch(console.error); -} + expect(members).toBeDefined(); + expect(Array.isArray(members)).toBe(true); + }); +}); diff --git a/tests/unit/run-all.test.ts b/tests/unit/run-all.test.ts deleted file mode 100644 index 73d5d75..0000000 --- a/tests/unit/run-all.test.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { wait } from "./test-utils"; - -import { testIntake } from "./intake.test"; -import { testEpics } from "./epic.test"; -import { testPage } from "./page.test"; -import { testProjects } from "./project.test"; -import { testLabels } from "./label.test"; -import { testStates } from "./state.test"; - -import { testWorkItemTypes } from "./work-item-types/types.test"; -import { testWorkItemTypesPropertiesAndOptions } from "./work-item-types/properties-options.test"; -import { testWorkItemPropertiesValues } from "./work-item-types/properties-values.test"; - -import { testWorkItems } from "./work-items/work-items.test"; -import { testWorkLogs } from "./work-items/work-logs.test"; -import { testRelations } from "./work-items/relations.test"; - -import { testModules } from "./module.test"; -import { testCycles } from "./cycle.test"; - -import { testCustomersWorkItems } from "./customers/work-items.test"; -import { testCustomersPropertiesOptionsAndValues } from "./customers/properties-options.test"; -import { testCustomers } from "./customers/customers.test"; -import { testCustomersRequests } from "./customers/requests.test"; - -import { testOAuth } from "./oauth.test"; -import { testComments } from "./work-items/comments.test"; -import { testLinks } from "./work-items/links.test"; -import { testActivities } from "./work-items/activities.test"; - -async function runAllTests() { - await testIntake(); - await testEpics(); - await testPage(); - - await wait(60); - await testProjects(); - await testLabels(); - await testStates(); - await wait(60); - - await testWorkItemTypes(); - await testWorkItemTypesPropertiesAndOptions(); - await testWorkItemPropertiesValues(); - await wait(60); - await testWorkItems(); - await testRelations(); - await testWorkLogs(); - - await testModules(); - await testCycles(); - - await wait(60); - await testCustomers(); - await testCustomersWorkItems(); - await testCustomersPropertiesOptionsAndValues(); - await testCustomersRequests(); - - await wait(60); - await testComments(); - await testLinks(); - await testActivities(); - - await wait(60); - await testOAuth(); -} - -if (require.main === module) { - runAllTests().catch(console.error); -} diff --git a/tests/unit/state.test.ts b/tests/unit/state.test.ts index 73c6be4..37ff92a 100644 --- a/tests/unit/state.test.ts +++ b/tests/unit/state.test.ts @@ -1,72 +1,75 @@ import { PlaneClient } from "../../src/client/plane-client"; import { State } from "../../src/models/State"; import { config } from "./constants"; -import { createTestClient } from "../helpers/test-utils"; +import { createTestClient, randomizeName } from "../helpers/test-utils"; +import { describeIf as describe } from "../helpers/conditional-tests"; -export async function testStates() { - const client = createTestClient(); +describe(!!(config.workspaceSlug && config.projectId), "State API Tests", () => { + let client: PlaneClient; + let workspaceSlug: string; + let projectId: string; + let state: State; - const workspaceSlug = config.workspaceSlug; - const projectId = config.projectId; - - if (!workspaceSlug || !projectId) { - console.error("workspaceSlug and projectId are required"); - return; - } - - const stateObj = await createState(client, workspaceSlug, projectId); - console.log("Created state: ", stateObj); + beforeAll(async () => { + client = createTestClient(); + workspaceSlug = config.workspaceSlug; + projectId = config.projectId; + }); - const retrievedState = await retrieveState(client, workspaceSlug, projectId, stateObj.id); - console.log("Retrieved state: ", retrievedState); + afterAll(async () => { + // Clean up created state + if (state?.id) { + try { + await client.states.delete(workspaceSlug, projectId, state.id); + } catch (error) { + console.warn("Failed to delete state:", error); + } + } + }); - const updatedState = await updateState(client, workspaceSlug, projectId, stateObj.id, stateObj); - console.log("Updated state: ", updatedState); + it("should create a state", async () => { + state = await client.states.create(workspaceSlug, projectId, { + name: randomizeName("Test State"), + description: "Test State Description", + group: "started", + color: "#9AA4BC", + }); - const states = await listStates(client, workspaceSlug, projectId); - console.log("Listed states: ", states); + expect(state).toBeDefined(); + expect(state.id).toBeDefined(); + expect(state.name).toContain("Test State"); + expect(state.description).toBe("Test State Description"); + expect(state.group).toBe("started"); + }); - await deleteState(client, workspaceSlug, projectId, stateObj.id); - console.log("State deleted: ", stateObj.id); -} + it("should retrieve a state", async () => { + const retrievedState = await client.states.retrieve(workspaceSlug, projectId, state.id!); -async function createState(client: PlaneClient, workspaceSlug: string, projectId: string) { - const state = await client.states.create(workspaceSlug, projectId, { - name: "Test State " + new Date().getTime(), - description: "Test State Description", - group: "started", - color: "#9AA4BC", + expect(retrievedState).toBeDefined(); + expect(retrievedState.id).toBe(state.id); + expect(retrievedState.name).toBe(state.name); + expect(retrievedState.description).toBe(state.description); }); - return state; -} -async function retrieveState(client: PlaneClient, workspaceSlug: string, projectId: string, stateId: string) { - const state = await client.states.retrieve(workspaceSlug, projectId, stateId); - return state; -} + it("should update a state", async () => { + const updatedState = await client.states.update(workspaceSlug, projectId, state.id!, { + description: "Updated Test State Description", + }); -async function updateState( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - stateId: string, - state: State -) { - const updatedState = await client.states.update(workspaceSlug, projectId, stateId, { - description: "Updated Test State Description", + expect(updatedState).toBeDefined(); + expect(updatedState.id).toBe(state.id); + expect(updatedState.description).toBe("Updated Test State Description"); }); - return updatedState; -} -async function listStates(client: PlaneClient, workspaceSlug: string, projectId: string) { - const states = await client.states.list(workspaceSlug, projectId); - return states; -} + it("should list states", async () => { + const states = await client.states.list(workspaceSlug, projectId); -async function deleteState(client: PlaneClient, workspaceSlug: string, projectId: string, stateId: string) { - await client.states.delete(workspaceSlug, projectId, stateId); -} + expect(states).toBeDefined(); + expect(Array.isArray(states.results)).toBe(true); + expect(states.results.length).toBeGreaterThan(0); -if (require.main === module) { - testStates().catch(console.error); -} + const foundState = states.results.find((s) => s.id === state.id); + expect(foundState).toBeDefined(); + expect(foundState?.description).toBe("Updated Test State Description"); + }); +}); diff --git a/tests/unit/work-item-types/properties-options.test.ts b/tests/unit/work-item-types/properties-options.test.ts index c28c13c..e3992e3 100644 --- a/tests/unit/work-item-types/properties-options.test.ts +++ b/tests/unit/work-item-types/properties-options.test.ts @@ -1,266 +1,145 @@ import { PlaneClient } from "../../../src/client/plane-client"; -import { PropertyType } from "../../../src/models/common"; -import { - WorkItemProperty, - WorkItemPropertyOption, - WorkItemPropertySettings, -} from "../../../src/models/WorkItemProperty"; +import { WorkItemProperty, WorkItemPropertyOption } from "../../../src/models/WorkItemProperty"; import { config } from "../constants"; -import { createTestClient } from "../../helpers/test-utils"; - -export async function testWorkItemTypesPropertiesAndOptions() { - const client = createTestClient(); - - const workspaceSlug = config.workspaceSlug; - const projectId = config.projectId; - const workItemTypeId = config.workItemTypeId; - - if (!workspaceSlug || !projectId || !workItemTypeId) { - console.error("workspaceSlug, projectId and workItemTypeId are required"); - return; - } - - // enable work item types if didn't already - await client.projects.update(workspaceSlug, projectId, { - is_issue_type_enabled: true, - }); - - // test the work item type properties - const workItemTypeProperty = await createWorkItemTypeProperty( - client, - workspaceSlug, - projectId, - workItemTypeId, - "TEXT", - { - display_format: "single-line", - } - ); - console.log("Created work item type property: ", workItemTypeProperty); - - const retrievedWorkItemTypeProperty = await retrieveWorkItemTypeProperty( - client, - workspaceSlug, - projectId, - workItemTypeId, - workItemTypeProperty.id - ); - console.log("Retrieved work item type property: ", retrievedWorkItemTypeProperty); - - const updatedWorkItemTypeProperty = await updateWorkItemTypeProperty( - client, - workspaceSlug, - projectId, - workItemTypeId, - workItemTypeProperty.id - ); - console.log("Updated work item type property: ", updatedWorkItemTypeProperty); - - const workItemTypeProperties = await listWorkItemTypeProperties(client, workspaceSlug, projectId, workItemTypeId); - console.log("Listed work item type properties: ", workItemTypeProperties); - - await deleteWorkItemTypeProperty(client, workspaceSlug, projectId, workItemTypeId, workItemTypeProperty.id); - console.log("Work item type property deleted: ", workItemTypeProperty.id); - - // test the work item type property options - // create a work item type property with property type OPTION - // use the work item type property id to create a work item property option - - const optionWorkItemTypeProperty = await createWorkItemTypeProperty( - client, - workspaceSlug, - projectId, - workItemTypeId, - "OPTION" - ); - console.log("Created option work item type property: ", optionWorkItemTypeProperty); - - if (!optionWorkItemTypeProperty.id) { - throw new Error("optionWorkItemTypeProperty ID is required to test work item property options"); +import { createTestClient, randomizeName } from "../../helpers/test-utils"; +import { describeIf as describe } from "../../helpers/conditional-tests"; + +describe( + !!(config.workspaceSlug && config.projectId && config.workItemTypeId), + "Work Item Type Properties and Options API Tests", + () => { + let client: PlaneClient; + let workspaceSlug: string; + let projectId: string; + let workItemTypeId: string; + let textProperty: WorkItemProperty; + let optionProperty: WorkItemProperty; + let propertyOption: WorkItemPropertyOption; + + beforeAll(async () => { + client = createTestClient(); + workspaceSlug = config.workspaceSlug; + projectId = config.projectId; + workItemTypeId = config.workItemTypeId; + + // Enable work item types if not already enabled + await client.projects.update(workspaceSlug, projectId, { + is_issue_type_enabled: true, + }); + }); + + it("should test complete work item type properties and options workflow", async () => { + // ===== TEST TEXT PROPERTY ===== + // Create a TEXT property + const textPropertyName = randomizeName("Test WI Type Property"); + textProperty = await client.workItemProperties.create(workspaceSlug, projectId, workItemTypeId, { + name: textPropertyName, + display_name: textPropertyName, + property_type: "TEXT", + settings: { + display_format: "single-line", + }, + is_required: false, + }); + + expect(textProperty).toBeDefined(); + expect(textProperty.id).toBeDefined(); + expect(textProperty.property_type).toBe("TEXT"); + + // Retrieve the property + const retrievedTextProperty = await client.workItemProperties.retrieve( + workspaceSlug, + projectId, + workItemTypeId, + textProperty.id! + ); + + expect(retrievedTextProperty).toBeDefined(); + expect(retrievedTextProperty.id).toBe(textProperty.id); + + // Update the property + const updatedTextPropertyName = randomizeName("Updated Test WI Type Property"); + const updatedTextProperty = await client.workItemProperties.update( + workspaceSlug, + projectId, + workItemTypeId, + textProperty.id!, + { + name: updatedTextPropertyName, + } + ); + + expect(updatedTextProperty).toBeDefined(); + expect(updatedTextProperty.id).toBe(textProperty.id); + + // List properties + const properties = await client.workItemProperties.list(workspaceSlug, projectId, workItemTypeId, { + limit: 10, + offset: 0, + }); + + expect(properties).toBeDefined(); + expect(Array.isArray(properties)).toBe(true); + const foundProperty = properties.find((p) => p.id === textProperty.id); + expect(foundProperty).toBeDefined(); + + // Delete the TEXT property + await client.workItemProperties.delete(workspaceSlug, projectId, workItemTypeId, textProperty.id!); + + // ===== TEST OPTION PROPERTY AND OPTIONS ===== + // Create an OPTION property + const optionPropertyName = randomizeName("Test Option Property"); + optionProperty = await client.workItemProperties.create(workspaceSlug, projectId, workItemTypeId, { + name: optionPropertyName, + display_name: optionPropertyName, + property_type: "OPTION", + is_required: false, + }); + + expect(optionProperty).toBeDefined(); + expect(optionProperty.id).toBeDefined(); + expect(optionProperty.property_type).toBe("OPTION"); + + // Create a property option + const optionName = randomizeName("Test Property Option"); + propertyOption = await client.workItemProperties.options.create(workspaceSlug, projectId, optionProperty.id!, { + name: optionName, + }); + + expect(propertyOption).toBeDefined(); + expect(propertyOption.id).toBeDefined(); + + // Retrieve the property option + const retrievedOption = await client.workItemProperties.options.retrieve( + workspaceSlug, + projectId, + optionProperty.id!, + propertyOption.id! + ); + + expect(retrievedOption).toBeDefined(); + expect(retrievedOption.id).toBe(propertyOption.id); + + // Update the property option + const updatedOptionName = randomizeName("Updated Property Option"); + const updatedOption = await client.workItemProperties.options.update( + workspaceSlug, + projectId, + optionProperty.id!, + propertyOption.id!, + { + name: updatedOptionName, + } + ); + + expect(updatedOption).toBeDefined(); + expect(updatedOption.id).toBe(propertyOption.id); + + // Delete the property option + await client.workItemProperties.options.delete(workspaceSlug, projectId, optionProperty.id!, propertyOption.id!); + + // Delete the OPTION property + await client.workItemProperties.delete(workspaceSlug, projectId, workItemTypeId, optionProperty.id!); + }); } - - const createdWorkItemPropertyOption = await createWorkItemPropertyOption( - client, - workspaceSlug, - projectId, - optionWorkItemTypeProperty.id - ); - console.log("Created work item property option: ", createdWorkItemPropertyOption); - - const retrievedWorkItemPropertyOption = await retrieveWorkItemPropertyOption( - client, - workspaceSlug, - projectId, - optionWorkItemTypeProperty.id, - createdWorkItemPropertyOption.id - ); - console.log("Retrieved work item property option: ", retrievedWorkItemPropertyOption); - - const updatedWorkItemPropertyOption = await updateWorkItemPropertyOption( - client, - workspaceSlug, - projectId, - optionWorkItemTypeProperty.id, - createdWorkItemPropertyOption.id - ); - console.log("Updated work item property option: ", updatedWorkItemPropertyOption); - - await deleteWorkItemPropertyOption( - client, - workspaceSlug, - projectId, - optionWorkItemTypeProperty.id, - createdWorkItemPropertyOption.id - ); - console.log("Work item property option deleted: ", createdWorkItemPropertyOption.id); - - await deleteWorkItemTypeProperty(client, workspaceSlug, projectId, workItemTypeId, optionWorkItemTypeProperty.id); - console.log("Option work item type property deleted: ", optionWorkItemTypeProperty.id); -} - -async function createWorkItemTypeProperty( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemTypeId: string, - propertyType: PropertyType, - settings?: WorkItemPropertySettings -): Promise { - const workItemTypeProperty = await client.workItemProperties.create(workspaceSlug, projectId, workItemTypeId, { - name: `Test WI Type Property ${new Date().getTime()}`, - display_name: `Test WI Type Property ${new Date().getTime()}`, - property_type: propertyType, - settings, - is_required: false, - }); - return workItemTypeProperty; -} - -async function retrieveWorkItemTypeProperty( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemTypeId: string, - workItemPropertyId: string -): Promise { - const workItemTypeProperty = await client.workItemProperties.retrieve( - workspaceSlug, - projectId, - workItemTypeId, - workItemPropertyId - ); - return workItemTypeProperty; -} - -async function listWorkItemTypeProperties( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemTypeId: string -): Promise { - const workItemTypeProperties = await client.workItemProperties.list(workspaceSlug, projectId, workItemTypeId, { - limit: 10, - offset: 0, - }); - return workItemTypeProperties; -} - -async function updateWorkItemTypeProperty( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemTypeId: string, - workItemPropertyId: string -): Promise { - const updatedWorkItemTypeProperty = await client.workItemProperties.update( - workspaceSlug, - projectId, - workItemTypeId, - workItemPropertyId, - { - name: `Updated Test WI Type Property ${new Date().getTime()}`, - } - ); - return updatedWorkItemTypeProperty; -} - -async function deleteWorkItemTypeProperty( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemTypeId: string, - workItemPropertyId: string -): Promise { - await client.workItemProperties.delete(workspaceSlug, projectId, workItemTypeId, workItemPropertyId); -} - -async function createWorkItemPropertyOption( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemPropertyId: string -): Promise { - const workItemTypePropertyOption = await client.workItemProperties.options.create( - workspaceSlug, - projectId, - workItemPropertyId, - { - name: `Test Property Option ${new Date().getTime()}`, - } - ); - return workItemTypePropertyOption; -} - -async function retrieveWorkItemPropertyOption( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemPropertyId: string, - workItemPropertyOptionId: string -): Promise { - const workItemTypePropertyOption = await client.workItemProperties.options.retrieve( - workspaceSlug, - projectId, - workItemPropertyId, - workItemPropertyOptionId - ); - return workItemTypePropertyOption; -} - -async function updateWorkItemPropertyOption( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemPropertyId: string, - workItemPropertyOptionId: string -): Promise { - const workItemTypePropertyOption = await client.workItemProperties.options.update( - workspaceSlug, - projectId, - workItemPropertyId, - workItemPropertyOptionId, - { - name: `Updated Property Option ${new Date().getTime()}`, - } - ); - return workItemTypePropertyOption; -} - -async function deleteWorkItemPropertyOption( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemPropertyId: string, - workItemPropertyOptionId: string -): Promise { - await client.workItemProperties.options.delete( - workspaceSlug, - projectId, - workItemPropertyId, - workItemPropertyOptionId - ); -} - -if (require.main === module) { - testWorkItemTypesPropertiesAndOptions().catch(console.error); -} +); diff --git a/tests/unit/work-item-types/properties-values.test.ts b/tests/unit/work-item-types/properties-values.test.ts index 4390eea..b5f4e1a 100644 --- a/tests/unit/work-item-types/properties-values.test.ts +++ b/tests/unit/work-item-types/properties-values.test.ts @@ -1,96 +1,63 @@ import { PlaneClient } from "../../../src/client/plane-client"; -import { WorkItemPropertyValues } from "../../../src/models/WorkItemProperty"; import { config } from "../constants"; -import { createTestClient } from "../../helpers/test-utils"; - -export async function testWorkItemPropertiesValues() { - const client = createTestClient(); - - const workspaceSlug = config.workspaceSlug; - const projectId = config.projectId; - const workItemId = config.workItemId; - const propertyId = config.customTextPropertyId; - - // enable work item types if didn't already - await client.projects.update(workspaceSlug, projectId, { - is_issue_type_enabled: true, - }); - - if (!workspaceSlug || !projectId || !workItemId || !propertyId) { - console.error("workItemId and propertyId are required to test work item properties and values"); - return; +import { createTestClient, randomizeName } from "../../helpers/test-utils"; +import { describeIf as describe } from "../../helpers/conditional-tests"; + +describe( + !!(config.workspaceSlug && config.projectId && config.workItemId && config.customTextPropertyId), + "Work Item Property Values API Tests", + () => { + let client: PlaneClient; + let workspaceSlug: string; + let projectId: string; + let workItemId: string; + let propertyId: string; + + beforeAll(async () => { + client = createTestClient(); + workspaceSlug = config.workspaceSlug; + projectId = config.projectId; + workItemId = config.workItemId; + propertyId = config.customTextPropertyId; + + // Enable work item types if not already enabled + await client.projects.update(workspaceSlug, projectId, { + is_issue_type_enabled: true, + }); + }); + + it("should test complete work item property values workflow", async () => { + // Create/update a work item property value + const testValue = randomizeName("Test WI Property Value"); + const workItemPropertyValue = await client.workItemProperties.values.create( + workspaceSlug, + projectId, + workItemId, + propertyId, + { + values: [{ value: testValue }], + } + ); + + expect(workItemPropertyValue).toBeDefined(); + + // Retrieve the work item property value + const retrievedWorkItemPropertyValue = await client.workItemProperties.values.retrieve( + workspaceSlug, + projectId, + workItemId, + propertyId + ); + + expect(retrievedWorkItemPropertyValue).toBeDefined(); + + // List all work item property values for the work item + const workItemPropertyValues = await client.workItemProperties.values.list(workspaceSlug, projectId, workItemId, { + limit: 10, + offset: 0, + }); + + expect(workItemPropertyValues).toBeDefined(); + }); } - - const workItemPropertyValue = await updateWorkItemPropertyValue( - client, - workspaceSlug, - projectId, - workItemId, - propertyId - ); - console.log("Created work item property value: ", workItemPropertyValue); - - const retrievedWorkItemPropertyValue = await retrieveWorkItemPropertyValue( - client, - workspaceSlug, - projectId, - workItemId, - propertyId - ); - console.log("Retrieved work item property value: ", retrievedWorkItemPropertyValue); - - const workItemPropertyValues = await listWorkItemPropertyValues(client, workspaceSlug, projectId, workItemId); - console.log("Listed work item property values: ", workItemPropertyValues); -} - -async function updateWorkItemPropertyValue( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemId: string, - propertyId: string -): Promise { - const workItemPropertyValue = await client.workItemProperties.values.create( - workspaceSlug, - projectId, - workItemId, - propertyId, - { - values: [{ value: `Test WI Property Value ${new Date().getTime()}` }], - } - ); - return workItemPropertyValue; -} - -async function retrieveWorkItemPropertyValue( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemId: string, - propertyId: string -): Promise { - const workItemPropertyValue = await client.workItemProperties.values.retrieve( - workspaceSlug, - projectId, - workItemId, - propertyId - ); - return workItemPropertyValue; -} - -async function listWorkItemPropertyValues( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemId: string -): Promise { - const workItemPropertyValues = await client.workItemProperties.values.list(workspaceSlug, projectId, workItemId, { - limit: 10, - offset: 0, - }); - return workItemPropertyValues; -} - -if (require.main === module) { - testWorkItemPropertiesValues().catch(console.error); -} +); diff --git a/tests/unit/work-item-types/types.test.ts b/tests/unit/work-item-types/types.test.ts index dd10ece..eef7883 100644 --- a/tests/unit/work-item-types/types.test.ts +++ b/tests/unit/work-item-types/types.test.ts @@ -1,95 +1,73 @@ import { PlaneClient } from "../../../src/client/plane-client"; -import { PaginatedResponse } from "../../../src/models/common"; import { WorkItemType } from "../../../src/models/WorkItemType"; import { config } from "../constants"; -import { createTestClient } from "../../helpers/test-utils"; +import { createTestClient, randomizeName } from "../../helpers/test-utils"; +import { describeIf as describe } from "../../helpers/conditional-tests"; -export async function testWorkItemTypes() { - const client = createTestClient(); +describe(!!(config.workspaceSlug && config.projectId), "Work Item Types API Tests", () => { + let client: PlaneClient; + let workspaceSlug: string; + let projectId: string; + let workItemType: WorkItemType; - const workspaceSlug = config.workspaceSlug; - const projectId = config.projectId; + beforeAll(async () => { + client = createTestClient(); + workspaceSlug = config.workspaceSlug; + projectId = config.projectId; - if (!workspaceSlug || !projectId) { - console.error("workspaceSlug and projectId are required"); - return; - } - - // enable work item types if didn't already - await client.projects.update(workspaceSlug, projectId, { - is_issue_type_enabled: true, + // Enable work item types if not already enabled + await client.projects.update(workspaceSlug, projectId, { + is_issue_type_enabled: true, + }); }); - const workItemType = await createWorkItemType(client, workspaceSlug, projectId); - console.log("Created work item type: ", workItemType); - - const retrievedWorkItemType = await retrieveWorkItemType(client, workspaceSlug, projectId, workItemType.id); - console.log("Retrieved work item type: ", retrievedWorkItemType); + afterAll(async () => { + // Clean up created work item type + if (workItemType?.id) { + try { + await client.workItemTypes.delete(workspaceSlug, projectId, workItemType.id); + } catch (error) { + console.warn("Failed to delete work item type:", error); + } + } + }); - const updatedWorkItemType = await updateWorkItemType(client, workspaceSlug, projectId, workItemType.id); - console.log("Updated work item type: ", updatedWorkItemType); + it("should create a work item type", async () => { + workItemType = await client.workItemTypes.create(workspaceSlug, projectId, { + name: randomizeName("Test WI Type"), + }); - const workItemTypes = await listWorkItemTypes(client, workspaceSlug, projectId); - console.log("Listed work item types: ", workItemTypes); + expect(workItemType).toBeDefined(); + expect(workItemType.id).toBeDefined(); + expect(workItemType.name).toContain("Test WI Type"); + }); - await deleteWorkItemType(client, workspaceSlug, projectId, workItemType.id); - console.log("Work item type deleted: ", workItemType.id); -} + it("should retrieve a work item type", async () => { + const retrievedWorkItemType = await client.workItemTypes.retrieve(workspaceSlug, projectId, workItemType.id!); -async function createWorkItemType( - client: PlaneClient, - workspaceSlug: string, - projectId: string -): Promise { - const workItemType = await client.workItemTypes.create(workspaceSlug, projectId, { - name: `Test WI Type ${new Date().getTime()}`, + expect(retrievedWorkItemType).toBeDefined(); + expect(retrievedWorkItemType.id).toBe(workItemType.id); + expect(retrievedWorkItemType.name).toBe(workItemType.name); }); - return workItemType; -} -async function retrieveWorkItemType( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemTypeId: string -): Promise { - const workItemType = await client.workItemTypes.retrieve(workspaceSlug, projectId, workItemTypeId); - return workItemType; -} + it("should update a work item type", async () => { + const updatedWorkItemType = await client.workItemTypes.update(workspaceSlug, projectId, workItemType.id!, { + name: randomizeName("Updated Test WI Type"), + }); -async function listWorkItemTypes( - client: PlaneClient, - workspaceSlug: string, - projectId: string -): Promise> { - const workItemTypes = await client.workItemTypes.list(workspaceSlug, projectId, { - limit: 10, - offset: 0, + expect(updatedWorkItemType).toBeDefined(); + expect(updatedWorkItemType.id).toBe(workItemType.id); + expect(updatedWorkItemType.name).toContain("Updated Test WI Type"); }); - return workItemTypes; -} -async function updateWorkItemType( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemTypeId: string -): Promise { - const updatedWorkItemType = await client.workItemTypes.update(workspaceSlug, projectId, workItemTypeId, { - name: `Updated Test WI Type ${new Date().getTime()}`, - }); - return updatedWorkItemType; -} + it("should list work item types", async () => { + const workItemTypes = await client.workItemTypes.list(workspaceSlug, projectId); -async function deleteWorkItemType( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemTypeId: string -): Promise { - await client.workItemTypes.delete(workspaceSlug, projectId, workItemTypeId); -} + expect(workItemTypes).toBeDefined(); + expect(Array.isArray(workItemTypes)).toBe(true); + expect(workItemTypes.length).toBeGreaterThan(0); -if (require.main === module) { - testWorkItemTypes().catch(console.error); -} + const foundType = workItemTypes.find((t) => t.id === workItemType.id); + expect(foundType).toBeDefined(); + }); +}); diff --git a/tests/unit/work-items/activities.test.ts b/tests/unit/work-items/activities.test.ts index 28fa207..6515f9a 100644 --- a/tests/unit/work-items/activities.test.ts +++ b/tests/unit/work-items/activities.test.ts @@ -1,42 +1,41 @@ import { PlaneClient } from "../../../src/client/plane-client"; import { config } from "../constants"; import { createTestClient } from "../../helpers/test-utils"; - -export async function testActivities() { - const client = createTestClient(); - - const workspaceSlug = config.workspaceSlug; - const projectId = config.projectId; - const workItemId = config.workItemId; - - if (!workspaceSlug || !projectId || !workItemId) { - console.error("workspaceSlug, projectId and workItemId are required"); - return; - } - - const activityResponse = await listActivities(client, workspaceSlug, projectId, workItemId); - console.log("activities list", activityResponse); - - const activity = await retrieveActivity(client, workspaceSlug, projectId, workItemId, activityResponse.results[0].id); - console.log("activity retrieve", activity); -} - -async function listActivities(client: PlaneClient, workspaceSlug: string, projectId: string, workItemId: string) { - const activities = await client.workItems.activities.list(workspaceSlug, projectId, workItemId); - return activities; -} - -async function retrieveActivity( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemId: string, - activityId: string -) { - const activity = await client.workItems.activities.retrieve(workspaceSlug, projectId, workItemId, activityId); - return activity; -} - -if (require.main === module) { - testActivities().catch(console.error); -} +import { describeIf as describe } from "../../helpers/conditional-tests"; + +describe(!!(config.workspaceSlug && config.projectId && config.workItemId), "Work Item Activities API Tests", () => { + let client: PlaneClient; + let workspaceSlug: string; + let projectId: string; + let workItemId: string; + + beforeAll(async () => { + client = createTestClient(); + workspaceSlug = config.workspaceSlug; + projectId = config.projectId; + workItemId = config.workItemId; + }); + + it("should list activities", async () => { + const activityResponse = await client.workItems.activities.list(workspaceSlug, projectId, workItemId); + + expect(activityResponse).toBeDefined(); + expect(Array.isArray(activityResponse.results)).toBe(true); + }); + + it("should retrieve an activity", async () => { + const activityResponse = await client.workItems.activities.list(workspaceSlug, projectId, workItemId); + + if (activityResponse.results.length > 0) { + const activity = await client.workItems.activities.retrieve( + workspaceSlug, + projectId, + workItemId, + activityResponse.results[0]!.id! + ); + + expect(activity).toBeDefined(); + expect(activity.id).toBe(activityResponse.results[0]!.id); + } + }); +}); diff --git a/tests/unit/work-items/comments.test.ts b/tests/unit/work-items/comments.test.ts index ebf5d85..a22ae8e 100644 --- a/tests/unit/work-items/comments.test.ts +++ b/tests/unit/work-items/comments.test.ts @@ -1,81 +1,75 @@ import { PlaneClient } from "../../../src/client/plane-client"; -import { WorkItemCommentUpdateRequest } from "../../../src/models/Comment"; +import { WorkItemComment } from "../../../src/models/Comment"; import { config } from "../constants"; import { createTestClient } from "../../helpers/test-utils"; +import { describeIf as describe } from "../../helpers/conditional-tests"; -export async function testComments() { - const client = createTestClient(); +describe(!!(config.workspaceSlug && config.projectId && config.workItemId), "Work Item Comments API Tests", () => { + let client: PlaneClient; + let workspaceSlug: string; + let projectId: string; + let workItemId: string; + let comment: WorkItemComment; - const workspaceSlug = config.workspaceSlug; - const projectId = config.projectId; - const workItemId = config.workItemId; - - if (!workspaceSlug || !projectId || !workItemId) { - console.error("workspaceSlug, projectId and workItemId are required"); - return; - } - - const comment = await createComment(client, workspaceSlug, projectId, workItemId); - console.log("Created comment: ", comment); + beforeAll(async () => { + client = createTestClient(); + workspaceSlug = config.workspaceSlug; + projectId = config.projectId; + workItemId = config.workItemId; + }); - const retrievedComment = await retrieveComment(client, workspaceSlug, projectId, workItemId, comment.id); - console.log("Retrieved comment: ", retrievedComment); + afterAll(async () => { + // Clean up created comment + if (comment?.id) { + try { + await client.workItems.comments.delete(workspaceSlug, projectId, workItemId, comment.id); + } catch (error) { + console.warn("Failed to delete comment:", error); + } + } + }); - const updatedComment = await updateComment(client, workspaceSlug, projectId, workItemId, comment.id); - console.log("Updated comment: ", updatedComment); + it("should create a comment", async () => { + comment = await client.workItems.comments.create(workspaceSlug, projectId, workItemId, { + comment_html: "

Test Comment

", + }); - const comments = await listComments(client, workspaceSlug, projectId, workItemId); - console.log("Listed comments: ", comments); + expect(comment).toBeDefined(); + expect(comment.id).toBeDefined(); + expect(comment.comment_html).toBe("

Test Comment

"); + }); - await deleteComment(client, workspaceSlug, projectId, workItemId, comment.id); - console.log("Deleted comment: ", comment.id); -} + it("should retrieve a comment", async () => { + const retrievedComment = await client.workItems.comments.retrieve( + workspaceSlug, + projectId, + workItemId, + comment.id! + ); -async function createComment(client: PlaneClient, workspaceSlug: string, projectId: string, workItemId: string) { - const comment = await client.workItems.comments.create(workspaceSlug, projectId, workItemId, { - comment_html: "

Test Comment

", + expect(retrievedComment).toBeDefined(); + expect(retrievedComment.id).toBe(comment.id); + expect(retrievedComment.comment_html).toBe(comment.comment_html); }); - return comment; -} -async function retrieveComment( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemId: string, - commentId: string -) { - const comment = await client.workItems.comments.retrieve(workspaceSlug, projectId, workItemId, commentId); - return comment; -} + it("should update a comment", async () => { + const updatedComment = await client.workItems.comments.update(workspaceSlug, projectId, workItemId, comment.id!, { + comment_html: "

Updated Test Comment

", + }); -async function updateComment( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemId: string, - commentId: string -) { - return await client.workItems.comments.update(workspaceSlug, projectId, workItemId, commentId, { - comment_html: "

Updated Test Comment

", + expect(updatedComment).toBeDefined(); + expect(updatedComment.id).toBe(comment.id); + expect(updatedComment.comment_html).toBe("

Updated Test Comment

"); }); -} -async function listComments(client: PlaneClient, workspaceSlug: string, projectId: string, workItemId: string) { - const comments = await client.workItems.comments.list(workspaceSlug, projectId, workItemId); - return comments; -} + it("should list comments", async () => { + const comments = await client.workItems.comments.list(workspaceSlug, projectId, workItemId); -async function deleteComment( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemId: string, - commentId: string -) { - await client.workItems.comments.delete(workspaceSlug, projectId, workItemId, commentId); -} + expect(comments).toBeDefined(); + expect(Array.isArray(comments.results)).toBe(true); + expect(comments.results.length).toBeGreaterThan(0); -if (require.main === module) { - testComments().catch(console.error); -} + const foundComment = comments.results.find((c) => c.id === comment.id); + expect(foundComment).toBeDefined(); + }); +}); diff --git a/tests/unit/work-items/links.test.ts b/tests/unit/work-items/links.test.ts index 08fac7f..87c4bc4 100644 --- a/tests/unit/work-items/links.test.ts +++ b/tests/unit/work-items/links.test.ts @@ -1,83 +1,75 @@ import { PlaneClient } from "../../../src/client/plane-client"; import { Link } from "../../../src/models/Link"; import { config } from "../constants"; -import { createTestClient } from "../../helpers/test-utils"; +import { createTestClient, randomizeName } from "../../helpers/test-utils"; +import { describeIf as describe } from "../../helpers/conditional-tests"; -export async function testLinks() { - const client = createTestClient(); +describe(!!(config.workspaceSlug && config.projectId && config.workItemId), "Work Item Links API Tests", () => { + let client: PlaneClient; + let workspaceSlug: string; + let projectId: string; + let workItemId: string; + let link: Link; - const workspaceSlug = config.workspaceSlug; - const projectId = config.projectId; - const workItemId = config.workItemId; - - if (!workspaceSlug || !projectId || !workItemId) { - console.error("workspaceSlug, projectId and workItemId are required"); - return; - } - - const link = await createLink(client, workspaceSlug, projectId, workItemId); - console.log("Created link: ", link); + beforeAll(async () => { + client = createTestClient(); + workspaceSlug = config.workspaceSlug; + projectId = config.projectId; + workItemId = config.workItemId; + }); - const retrievedLink = await retrieveLink(client, workspaceSlug, projectId, workItemId, link.id); - console.log("Retrieved link: ", retrievedLink); + afterAll(async () => { + // Clean up created link + if (link?.id) { + try { + await client.workItems.links.delete(workspaceSlug, projectId, workItemId, link.id); + } catch (error) { + console.warn("Failed to delete link:", error); + } + } + }); - const updatedLink = await updateLink(client, workspaceSlug, projectId, workItemId, link.id); - console.log("Updated link: ", updatedLink); + it("should create a link", async () => { + link = await client.workItems.links.create(workspaceSlug, projectId, workItemId, { + title: randomizeName("Test Link"), + url: "https://test.com", + }); - const links = await listLinks(client, workspaceSlug, projectId, workItemId); - console.log("Listed links: ", links); + expect(link).toBeDefined(); + expect(link.id).toBeDefined(); + expect(link.title).toContain("Test Link"); + expect(link.url).toBe("https://test.com"); + }); - await deleteLink(client, workspaceSlug, projectId, workItemId, link.id); - console.log("Deleted link: ", link.id); -} + it("should retrieve a link", async () => { + const retrievedLink = await client.workItems.links.retrieve(workspaceSlug, projectId, workItemId, link.id!); -async function createLink(client: PlaneClient, workspaceSlug: string, projectId: string, workItemId: string) { - const link = await client.workItems.links.create(workspaceSlug, projectId, workItemId, { - title: "Test Link", - url: "https://test.com", + expect(retrievedLink).toBeDefined(); + expect(retrievedLink.id).toBe(link.id); + expect(retrievedLink.title).toBe(link.title); }); - return link; -} -async function retrieveLink( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemId: string, - linkId: string -) { - const link = await client.workItems.links.retrieve(workspaceSlug, projectId, workItemId, linkId); - return link; -} + it("should update a link", async () => { + const updatedLink = await client.workItems.links.update(workspaceSlug, projectId, workItemId, link.id!, { + title: randomizeName("Updated Test Link"), + url: "https://updated.com", + }); -async function updateLink( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemId: string, - linkId: string -) { - return await client.workItems.links.update(workspaceSlug, projectId, workItemId, linkId, { - title: "Updated Test Link", - url: "https://updated.com", + expect(updatedLink).toBeDefined(); + expect(updatedLink.id).toBe(link.id); + expect(updatedLink.title).toContain("Updated Test Link"); + expect(updatedLink.url).toBe("https://updated.com"); }); -} -async function listLinks(client: PlaneClient, workspaceSlug: string, projectId: string, workItemId: string) { - const links = await client.workItems.links.list(workspaceSlug, projectId, workItemId); - return links; -} + it("should list links", async () => { + const linksResponse = await client.workItems.links.list(workspaceSlug, projectId, workItemId); -async function deleteLink( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemId: string, - linkId: string -) { - await client.workItems.links.delete(workspaceSlug, projectId, workItemId, linkId); -} + expect(linksResponse).toBeDefined(); + expect(linksResponse.results).toBeDefined(); + expect(Array.isArray(linksResponse.results)).toBe(true); + expect(linksResponse.results.length).toBeGreaterThan(0); -if (require.main === module) { - testLinks().catch(console.error); -} + const foundLink = linksResponse.results.find((l) => l.id === link.id); + expect(foundLink).toBeDefined(); + }); +}); diff --git a/tests/unit/work-items/relations.test.ts b/tests/unit/work-items/relations.test.ts index a749276..d5549fd 100644 --- a/tests/unit/work-items/relations.test.ts +++ b/tests/unit/work-items/relations.test.ts @@ -1,62 +1,54 @@ import { PlaneClient } from "../../../src/client/plane-client"; -import { WorkItemRelationCreateRequest, WorkItemRelationRemoveRequest } from "../../../src/models/WorkItemRelation"; import { config } from "../constants"; import { createTestClient } from "../../helpers/test-utils"; - -export async function testRelations() { - const client = createTestClient(); - - const workspaceSlug = config.workspaceSlug; - const projectId = config.projectId; - const workItemId = config.workItemId; - const workItemId2 = config.workItemId2; - - if (!workspaceSlug || !projectId || !workItemId || !workItemId2) { - console.error("workspaceSlug, projectId, workItemId and workItemId2 are required"); - return; +import { describeIf as describe } from "../../helpers/conditional-tests"; +import { WorkItemRelationResponse } from "../../../src/models/WorkItemRelation"; +describe( + !!(config.workspaceSlug && config.projectId && config.workItemId && config.workItemId2), + "Work Item Relations API Tests", + () => { + let client: PlaneClient; + let workspaceSlug: string; + let projectId: string; + let workItemId: string; + let workItemId2: string; + let relatedWorkItemId: string; + + beforeAll(async () => { + client = createTestClient(); + workspaceSlug = config.workspaceSlug; + projectId = config.projectId; + workItemId = config.workItemId; + workItemId2 = config.workItemId2; + + // Get the actual work item ID from the identifier + const workItem2 = await client.workItems.retrieveByIdentifier(workspaceSlug, workItemId2); + relatedWorkItemId = workItem2.id!; + }); + + it("should create a relation", async () => { + const relationData = await client.workItems.relations.create(workspaceSlug, projectId, workItemId, { + relation_type: "blocking", + issues: [relatedWorkItemId], + }); + + expect(relationData).toBeDefined(); + }); + + it("should list relations", async () => { + const relations = await client.workItems.relations.list(workspaceSlug, projectId, workItemId); + + expect(relations).toBeDefined(); + expect(relations.blocking).toContain(relatedWorkItemId); + }); + + it("should delete a relation", async () => { + await client.workItems.relations.delete(workspaceSlug, projectId, workItemId, { + related_issue: relatedWorkItemId, + }); + + const relations = await client.workItems.relations.list(workspaceSlug, projectId, workItemId); + expect(relations.blocking).not.toContain(relatedWorkItemId); + }); } - - const workItem2 = await client.workItems.retrieveByIdentifier(workspaceSlug, workItemId2); - - const relationData = await createRelation(client, workspaceSlug, projectId, workItemId, { - relation_type: "blocking", - issues: [workItem2.id], - }); - console.log("Created relation: ", relationData); - - const relations = await listRelations(client, workspaceSlug, projectId, workItemId); - console.log("Listed relations: ", relations); - - await deleteRelation(client, workspaceSlug, projectId, workItemId, { - related_issue: workItem2.id, - }); - console.log("Deleted relation: ", workItem2.id); -} - -async function createRelation( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemId: string, - relationData: WorkItemRelationCreateRequest -) { - return client.workItems.relations.create(workspaceSlug, projectId, workItemId, relationData); -} - -async function listRelations(client: PlaneClient, workspaceSlug: string, projectId: string, workItemId: string) { - return client.workItems.relations.list(workspaceSlug, projectId, workItemId); -} - -async function deleteRelation( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemId: string, - relationData: WorkItemRelationRemoveRequest -) { - return client.workItems.relations.delete(workspaceSlug, projectId, workItemId, relationData); -} - -if (require.main === module) { - testRelations().catch(console.error); -} +); diff --git a/tests/unit/work-items/work-items.test.ts b/tests/unit/work-items/work-items.test.ts index 8e45696..6d4f5b9 100644 --- a/tests/unit/work-items/work-items.test.ts +++ b/tests/unit/work-items/work-items.test.ts @@ -1,109 +1,106 @@ import { PlaneClient } from "../../../src/client/plane-client"; +import { WorkItem } from "../../../src/models/WorkItem"; import { config } from "../constants"; -import { createTestClient } from "../../helpers/test-utils"; +import { createTestClient, randomizeName } from "../../helpers/test-utils"; +import { describeIf as describe } from "../../helpers/conditional-tests"; + +describe(!!(config.workspaceSlug && config.projectId && config.userId), "Work Items API Tests", () => { + let client: PlaneClient; + let workspaceSlug: string; + let projectId: string; + let userId: string; + let workItem: WorkItem; + + beforeAll(async () => { + client = createTestClient(); + workspaceSlug = config.workspaceSlug; + projectId = config.projectId; + userId = config.userId; + }); -export async function testWorkItems() { - const client = createTestClient(); + afterAll(async () => { + // Clean up created work item + if (workItem?.id) { + try { + await client.workItems.delete(workspaceSlug, projectId, workItem.id); + } catch (error) { + console.warn("Failed to delete work item:", error); + } + } + }); - const workspaceSlug = config.workspaceSlug; - const projectId = config.projectId; + it("should create a work item", async () => { + const name = randomizeName(); + workItem = await client.workItems.create(workspaceSlug, projectId, { + name, + description_html: "

A work item created via the Plane SDK

", + }); + + expect(workItem).toBeDefined(); + expect(workItem.id).toBeDefined(); + expect(workItem.name).toContain(name); + expect(workItem.description_html).toBe("

A work item created via the Plane SDK

"); + }); - if (!workspaceSlug || !projectId) { - console.error("workspaceSlug and projectId are required"); - return; - } + it("should retrieve a work item", async () => { + const retrievedWorkItem = await client.workItems.retrieve(workspaceSlug, projectId, workItem.id!); - const workItem = await createWorkItem(client, workspaceSlug, projectId); - console.log("Created work item: ", workItem); - await new Promise((resolve) => setTimeout(resolve, 1000)); + expect(retrievedWorkItem).toBeDefined(); + expect(retrievedWorkItem.id).toBe(workItem.id); + expect(retrievedWorkItem.name).toBe(workItem.name); + }); - const retrievedWorkItem = await retrieveWorkItem(client, workspaceSlug, projectId, workItem.id); - console.log("Retrieved work item: ", retrievedWorkItem); - await new Promise((resolve) => setTimeout(resolve, 1000)); + it("should update a work item", async () => { + const states = await client.states.list(workspaceSlug, projectId); + const labels = await client.labels.list(workspaceSlug, projectId); + + const label = labels.results[0]; + const state = states.results[0]; + + const updatedWorkItem = await client.workItems.update(workspaceSlug, projectId, workItem.id!, { + name: `${workItem.name} - Updated`, + description_html: "

Updated Test Work Item Description

", + state: state ? state.id : undefined, + assignees: [userId], + labels: label ? [label.id] : undefined, + }); + + expect(updatedWorkItem).toBeDefined(); + expect(updatedWorkItem.id).toBe(workItem.id); + expect(updatedWorkItem.name).toBe(`${workItem.name} - Updated`); + expect(updatedWorkItem.description_html).toBe("

Updated Test Work Item Description

"); + }); - const updatedWorkItem = await updateWorkItem(client, workspaceSlug, projectId, workItem.id); - console.log("Updated work item: ", updatedWorkItem); + it("should list work items", async () => { + const workItems = await client.workItems.list(workspaceSlug, projectId); - await new Promise((resolve) => setTimeout(resolve, 1000)); - const workItems = await listWorkItems(client, workspaceSlug, projectId); - console.log("Listed work items: ", workItems); + expect(workItems).toBeDefined(); + expect(Array.isArray(workItems.results)).toBe(true); + expect(workItems.results.length).toBeGreaterThan(0); - await new Promise((resolve) => setTimeout(resolve, 1000)); - const workItemByIdentifier = await retrieveWorkItemByIdentifier( - client, - workspaceSlug, - projectId, - workItem.sequence_id! - ); - console.log("Retrieved work item by identifier: ", workItemByIdentifier); - await new Promise((resolve) => setTimeout(resolve, 1000)); + const foundWorkItem = workItems.results.find((wi) => wi.id === workItem.id); + expect(foundWorkItem).toBeDefined(); + }); - const searchedWorkItems = await searchWorkItems(client, workspaceSlug, projectId, workItemByIdentifier.name); - console.log("Searched work items: ", searchedWorkItems); + it("should retrieve work item by identifier", async () => { + const project = await client.projects.retrieve(workspaceSlug, projectId); + const workItemByIdentifier = await client.workItems.retrieveByIdentifier( + workspaceSlug, + `${project.identifier}-${workItem.sequence_id}`, + ["project"] + ); - await new Promise((resolve) => setTimeout(resolve, 1000)); + expect(workItemByIdentifier).toBeDefined(); + expect(workItemByIdentifier.id).toBe(workItem.id); + }); - await deleteWorkItem(client, workspaceSlug, projectId, workItem.id); - console.log("Work item deleted: ", workItem.id); -} + it("should search work items", async () => { + const searchedWorkItemsResponse = await client.workItems.search(workspaceSlug, workItem.name); -async function createWorkItem(client: PlaneClient, workspaceSlug: string, projectId: string) { - const workItem = await client.workItems.create(workspaceSlug, projectId, { - name: "Test Work Item", - description_html: "

A work item created via the Plane SDK

", - }); - return workItem; -} - -async function retrieveWorkItem(client: PlaneClient, workspaceSlug: string, projectId: string, workItemId: string) { - const workItem = await client.workItems.retrieve(workspaceSlug, projectId, workItemId); - return workItem; -} - -async function updateWorkItem(client: PlaneClient, workspaceSlug: string, projectId: string, workItemId: string) { - const states = await client.states.list(workspaceSlug, projectId); - const labels = await client.labels.list(workspaceSlug, projectId); - - const label = labels.results[0]; - const state = states.results[0]; - - const updatedWorkItem = await client.workItems.update(workspaceSlug, projectId, workItemId, { - name: "Updated Test Work Item", - description_html: "

Updated Test Work Item Description

", - state: state ? state.id : undefined, - assignees: [config.userId], - labels: label ? [label.id] : undefined, + expect(searchedWorkItemsResponse.issues).toBeDefined(); + expect(Array.isArray(searchedWorkItemsResponse.issues)).toBe(true); + expect(searchedWorkItemsResponse.issues.length).toBeGreaterThan(0); + const foundWorkItem = searchedWorkItemsResponse.issues.find((wi) => wi.id === workItem.id); + expect(foundWorkItem).toBeDefined(); }); - return updatedWorkItem; -} - -async function listWorkItems(client: PlaneClient, workspaceSlug: string, projectId: string) { - const workItems = await client.workItems.list(workspaceSlug, projectId); - return workItems; -} - -async function deleteWorkItem(client: PlaneClient, workspaceSlug: string, projectId: string, workItemId: string) { - await client.workItems.delete(workspaceSlug, projectId, workItemId); -} - -async function retrieveWorkItemByIdentifier( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - identifier: number -) { - const project = await client.projects.retrieve(workspaceSlug, projectId); - const workItem = await client.workItems.retrieveByIdentifier(workspaceSlug, `${project.identifier}-${identifier}`, [ - "project", - ]); - return workItem; -} - -async function searchWorkItems(client: PlaneClient, workspaceSlug: string, projectId: string, query: string) { - const workItems = await client.workItems.search(workspaceSlug, projectId, query); - return workItems; -} - -if (require.main === module) { - testWorkItems().catch(console.error); -} +}); diff --git a/tests/unit/work-items/work-logs.test.ts b/tests/unit/work-items/work-logs.test.ts index 9bcbc4b..788f1d1 100644 --- a/tests/unit/work-items/work-logs.test.ts +++ b/tests/unit/work-items/work-logs.test.ts @@ -1,73 +1,69 @@ import { PlaneClient } from "../../../src/client/plane-client"; +import { WorkLog } from "../../../src/models/WorkLog"; import { config } from "../constants"; import { createTestClient } from "../../helpers/test-utils"; +import { describeIf as describe } from "../../helpers/conditional-tests"; -export async function testWorkLogs() { - const client = createTestClient(); +describe(!!(config.workspaceSlug && config.projectId && config.workItemId), "Work Logs API Tests", () => { + let client: PlaneClient; + let workspaceSlug: string; + let projectId: string; + let workItemId: string; + let workLog: WorkLog; - const workspaceSlug = config.workspaceSlug; - const projectId = config.projectId; - const workItemId = config.workItemId; + beforeAll(async () => { + client = createTestClient(); + workspaceSlug = config.workspaceSlug; + projectId = config.projectId; + workItemId = config.workItemId; - if (!workspaceSlug || !projectId || !workItemId) { - console.error("workspaceSlug, projectId and workItemId are required"); - return; - } - - await client.projects.update(workspaceSlug, projectId, { - is_time_tracking_enabled: true, + // Enable time tracking + await client.projects.update(workspaceSlug, projectId, { + is_time_tracking_enabled: true, + }); }); - const project = await client.projects.retrieve(workspaceSlug, projectId); - - console.log("Time tracking enabled: ", project.is_time_tracking_enabled); + afterAll(async () => { + // Clean up created work log + if (workLog?.id) { + try { + await client.workItems.workLogs.delete(workspaceSlug, projectId, workItemId, workLog.id); + } catch (error) { + console.warn("Failed to delete work log:", error); + } + } + }); - const workLog = await createWorkLog(client, workspaceSlug, projectId, workItemId); - console.log("Created work log: ", workLog); + it("should create a work log", async () => { + workLog = await client.workItems.workLogs.create(workspaceSlug, projectId, workItemId, { + duration: 30, + description: "Test work log", + }); - const workLogs = await listWorkLogs(client, workspaceSlug, projectId, workItemId); - console.log("Listed work logs: ", workLogs); + expect(workLog).toBeDefined(); + expect(workLog.id).toBeDefined(); + expect(workLog.duration).toBe(30); + expect(workLog.description).toBe("Test work log"); + }); - const updatedWorkLog = await updateWorkLog(client, workspaceSlug, projectId, workItemId, workLog.id); - console.log("Updated work log: ", updatedWorkLog); + it("should list work logs", async () => { + const workLogs = await client.workItems.workLogs.list(workspaceSlug, projectId, workItemId); - await deleteWorkLog(client, workspaceSlug, projectId, workItemId, workLog.id); - console.log("Deleted work log: ", workLog.id); -} + expect(workLogs).toBeDefined(); + expect(Array.isArray(workLogs)).toBe(true); + expect(workLogs.length).toBeGreaterThan(0); -async function createWorkLog(client: PlaneClient, workspaceSlug: string, projectId: string, workItemId: string) { - return client.workItems.workLogs.create(workspaceSlug, projectId, workItemId, { - duration: 30, - description: "Test work log", + const foundWorkLog = workLogs.find((wl) => wl.id === workLog.id); + expect(foundWorkLog).toBeDefined(); }); -} -async function listWorkLogs(client: PlaneClient, workspaceSlug: string, projectId: string, workItemId: string) { - return client.workItems.workLogs.list(workspaceSlug, projectId, workItemId); -} + it("should update a work log", async () => { + const updatedWorkLog = await client.workItems.workLogs.update(workspaceSlug, projectId, workItemId, workLog.id!, { + description: "Updated test work log", + }); -async function updateWorkLog( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemId: string, - workLogId: string -) { - return client.workItems.workLogs.update(workspaceSlug, projectId, workItemId, workLogId, { - description: "Updated test work log", + expect(updatedWorkLog).toBeDefined(); + expect(updatedWorkLog.id).toBe(workLog.id); + expect(updatedWorkLog.description).toBe("Updated test work log"); }); -} - -async function deleteWorkLog( - client: PlaneClient, - workspaceSlug: string, - projectId: string, - workItemId: string, - workLogId: string -) { - return client.workItems.workLogs.delete(workspaceSlug, projectId, workItemId, workLogId); -} - -if (require.main === module) { - testWorkLogs().catch(console.error); -} +});