syncable-entity-testing — community syncable-entity-testing, twenty, community, ide skills, Claude Code, Cursor, Windsurf

v1.0.0
GitHub

About this Skill

Perfect for Python Analysis Agents needing advanced entity testing capabilities. Building a modern alternative to Salesforce, powered by the community.

twentyhq twentyhq
[0]
[0]
Updated: 3/5/2026

Agent Capability Analysis

The syncable-entity-testing skill by twentyhq is an open-source community AI agent skill for Claude Code and other IDE workflows, helping agents execute tasks with better context, repeatability, and domain-specific guidance.

Ideal Agent Persona

Perfect for Python Analysis Agents needing advanced entity testing capabilities.

Core Value

Empowers agents to generate comprehensive test suites covering all validation scenarios, input transpilation exceptions, and successful use cases using libraries like 'unittest' and protocols like 'HTTP'.

Capabilities Granted for syncable-entity-testing

Automating integration testing for syncable entities
Generating test cases for failing scenarios
Debugging successful use cases

! Prerequisites & Limits

  • Requires active database connection
  • Python 3.10+ only
Labs Demo

Browser Sandbox Environment

⚡️ Ready to unleash?

Experience this Agent in a zero-setup browser environment powered by WebContainers. No installation required.

Boot Container Sandbox

syncable-entity-testing

Building a modern alternative to Salesforce, powered by the community.

SKILL.md
Readonly

Syncable Entity: Integration Testing (Step 6/6 - MANDATORY)

Purpose: Create comprehensive test suite covering all validation scenarios, input transpilation exceptions, and successful use cases.

When to use: After completing Steps 1-5. Integration tests are REQUIRED for all syncable entities.


Quick Start

Tests must cover:

  1. Failing scenarios - All validator exceptions and input transpilation errors
  2. Successful scenarios - All CRUD operations and edge cases
  3. Test utilities - Reusable query factories and helper functions

Test pattern: Two-file pattern (query factory + wrapper) for each operation.


Step 1: Create Test Utilities

Pattern: Query Factory

File: test/integration/metadata/suites/my-entity/utils/create-my-entity-query-factory.util.ts

typescript
1import gql from 'graphql-tag'; 2import { type PerformMetadataQueryParams } from 'test/integration/metadata/types/perform-metadata-query.type'; 3import { type CreateMyEntityInput } from 'src/engine/metadata-modules/my-entity/dtos/create-my-entity.input'; 4 5export type CreateMyEntityFactoryInput = CreateMyEntityInput; 6 7const DEFAULT_MY_ENTITY_GQL_FIELDS = ` 8 id 9 name 10 label 11 description 12 isCustom 13 createdAt 14 updatedAt 15`; 16 17export const createMyEntityQueryFactory = ({ 18 input, 19 gqlFields = DEFAULT_MY_ENTITY_GQL_FIELDS, 20}: PerformMetadataQueryParams<CreateMyEntityFactoryInput>) => ({ 21 query: gql` 22 mutation CreateMyEntity($input: CreateMyEntityInput!) { 23 createMyEntity(input: $input) { 24 ${gqlFields} 25 } 26 } 27 `, 28 variables: { 29 input, 30 }, 31});

Pattern: Wrapper Utility

File: test/integration/metadata/suites/my-entity/utils/create-my-entity.util.ts

typescript
1import { 2 type CreateMyEntityFactoryInput, 3 createMyEntityQueryFactory, 4} from 'test/integration/metadata/suites/my-entity/utils/create-my-entity-query-factory.util'; 5import { makeMetadataAPIRequest } from 'test/integration/metadata/suites/utils/make-metadata-api-request.util'; 6import { type CommonResponseBody } from 'test/integration/metadata/types/common-response-body.type'; 7import { type PerformMetadataQueryParams } from 'test/integration/metadata/types/perform-metadata-query.type'; 8import { warnIfErrorButNotExpectedToFail } from 'test/integration/metadata/utils/warn-if-error-but-not-expected-to-fail.util'; 9import { warnIfNoErrorButExpectedToFail } from 'test/integration/metadata/utils/warn-if-no-error-but-expected-to-fail.util'; 10import { type MyEntityDto } from 'src/engine/metadata-modules/my-entity/dtos/my-entity.dto'; 11 12export const createMyEntity = async ({ 13 input, 14 gqlFields, 15 expectToFail = false, 16 token, 17}: PerformMetadataQueryParams<CreateMyEntityFactoryInput>): CommonResponseBody<{ 18 createMyEntity: MyEntityDto; 19}> => { 20 const graphqlOperation = createMyEntityQueryFactory({ 21 input, 22 gqlFields, 23 }); 24 25 const response = await makeMetadataAPIRequest(graphqlOperation, token); 26 27 if (expectToFail === true) { 28 warnIfNoErrorButExpectedToFail({ 29 response, 30 errorMessage: 'My entity creation should have failed but did not', 31 }); 32 } 33 34 if (expectToFail === false) { 35 warnIfErrorButNotExpectedToFail({ 36 response, 37 errorMessage: 'My entity creation has failed but should not', 38 }); 39 } 40 41 return { data: response.body.data, errors: response.body.errors }; 42};

Required utilities (follow same pattern):

  • update-my-entity-query-factory.util.ts + update-my-entity.util.ts
  • delete-my-entity-query-factory.util.ts + delete-my-entity.util.ts

Step 2: Failing Creation Tests

File: test/integration/metadata/suites/my-entity/failing-my-entity-creation.integration-spec.ts

typescript
1import { expectOneNotInternalServerErrorSnapshot } from 'test/integration/graphql/utils/expect-one-not-internal-server-error-snapshot.util'; 2import { createMyEntity } from 'test/integration/metadata/suites/my-entity/utils/create-my-entity.util'; 3import { deleteMyEntity } from 'test/integration/metadata/suites/my-entity/utils/delete-my-entity.util'; 4import { 5 eachTestingContextFilter, 6 type EachTestingContext, 7} from 'twenty-shared/testing'; 8import { isDefined } from 'twenty-shared/utils'; 9import { type CreateMyEntityInput } from 'src/engine/metadata-modules/my-entity/dtos/create-my-entity.input'; 10 11type TestContext = { 12 input: CreateMyEntityInput; 13}; 14 15type GlobalTestContext = { 16 existingEntityLabel: string; 17 existingEntityName: string; 18}; 19 20const globalTestContext: GlobalTestContext = { 21 existingEntityLabel: 'Existing Test Entity', 22 existingEntityName: 'existingTestEntity', 23}; 24 25type CreateMyEntityTestingContext = EachTestingContext<TestContext>[]; 26 27describe('My entity creation should fail', () => { 28 let existingEntityId: string | undefined; 29 30 beforeAll(async () => { 31 // Setup: Create entity for uniqueness tests 32 const { data } = await createMyEntity({ 33 expectToFail: false, 34 input: { 35 name: globalTestContext.existingEntityName, 36 label: globalTestContext.existingEntityLabel, 37 }, 38 }); 39 40 existingEntityId = data.createMyEntity.id; 41 }); 42 43 afterAll(async () => { 44 // Cleanup 45 if (isDefined(existingEntityId)) { 46 await deleteMyEntity({ 47 expectToFail: false, 48 input: { id: existingEntityId }, 49 }); 50 } 51 }); 52 53 const failingMyEntityCreationTestCases: CreateMyEntityTestingContext = [ 54 // Input transpilation validation 55 { 56 title: 'when name is missing', 57 context: { 58 input: { 59 label: 'Entity Missing Name', 60 } as CreateMyEntityInput, 61 }, 62 }, 63 { 64 title: 'when label is missing', 65 context: { 66 input: { 67 name: 'entityMissingLabel', 68 } as CreateMyEntityInput, 69 }, 70 }, 71 { 72 title: 'when name is empty string', 73 context: { 74 input: { 75 name: '', 76 label: 'Empty Name Entity', 77 }, 78 }, 79 }, 80 81 // Validator business logic 82 { 83 title: 'when name already exists (uniqueness)', 84 context: { 85 input: { 86 name: globalTestContext.existingEntityName, 87 label: 'Duplicate Name Entity', 88 }, 89 }, 90 }, 91 { 92 title: 'when trying to create standard entity', 93 context: { 94 input: { 95 name: 'myEntity', 96 label: 'Standard Entity', 97 isCustom: false, 98 } as CreateMyEntityInput, 99 }, 100 }, 101 102 // Foreign key validation 103 { 104 title: 'when parentEntityId does not exist', 105 context: { 106 input: { 107 name: 'invalidParentEntity', 108 label: 'Invalid Parent Entity', 109 parentEntityId: '00000000-0000-0000-0000-000000000000', 110 }, 111 }, 112 }, 113 ]; 114 115 it.each(eachTestingContextFilter(failingMyEntityCreationTestCases))( 116 '$title', 117 async ({ context }) => { 118 const { errors } = await createMyEntity({ 119 expectToFail: true, 120 input: context.input, 121 }); 122 123 expectOneNotInternalServerErrorSnapshot({ 124 errors, 125 }); 126 }, 127 ); 128});

Test coverage requirements:

  • ✅ Missing required fields
  • ✅ Empty strings
  • ✅ Invalid format
  • ✅ Uniqueness violations
  • ✅ Standard entity protection
  • ✅ Foreign key validation

Step 3: Successful Creation Tests

File: test/integration/metadata/suites/my-entity/successful-my-entity-creation.integration-spec.ts

typescript
1import { createMyEntity } from 'test/integration/metadata/suites/my-entity/utils/create-my-entity.util'; 2import { deleteMyEntity } from 'test/integration/metadata/suites/my-entity/utils/delete-my-entity.util'; 3import { type CreateMyEntityInput } from 'src/engine/metadata-modules/my-entity/dtos/create-my-entity.input'; 4 5describe('My entity creation should succeed', () => { 6 let createdEntityId: string; 7 8 afterEach(async () => { 9 if (createdEntityId) { 10 await deleteMyEntity({ 11 expectToFail: false, 12 input: { id: createdEntityId }, 13 }); 14 } 15 }); 16 17 it('should create entity with minimal required input', async () => { 18 const { data } = await createMyEntity({ 19 expectToFail: false, 20 input: { 21 name: 'minimalEntity', 22 label: 'Minimal Entity', 23 }, 24 }); 25 26 createdEntityId = data?.createMyEntity?.id; 27 28 expect(data.createMyEntity).toMatchObject({ 29 id: expect.any(String), 30 name: 'minimalEntity', 31 label: 'Minimal Entity', 32 description: null, 33 isCustom: true, 34 createdAt: expect.any(String), 35 updatedAt: expect.any(String), 36 }); 37 }); 38 39 it('should create entity with all optional fields', async () => { 40 const input = { 41 name: 'fullEntity', 42 label: 'Full Entity', 43 description: 'Entity with all fields specified', 44 } as const satisfies CreateMyEntityInput; 45 46 const { data } = await createMyEntity({ 47 expectToFail: false, 48 input, 49 }); 50 51 createdEntityId = data?.createMyEntity?.id; 52 53 expect(data.createMyEntity).toMatchObject({ 54 id: expect.any(String), 55 name: 'fullEntity', 56 label: 'Full Entity', 57 description: 'Entity with all fields specified', 58 isCustom: true, 59 }); 60 }); 61 62 it('should sanitize input by trimming whitespace', async () => { 63 const { data } = await createMyEntity({ 64 expectToFail: false, 65 input: { 66 name: ' entityWithSpaces ', 67 label: ' Entity With Spaces ', 68 description: ' Description with spaces ', 69 }, 70 }); 71 72 createdEntityId = data?.createMyEntity?.id; 73 74 expect(data.createMyEntity).toMatchObject({ 75 id: expect.any(String), 76 name: 'entityWithSpaces', 77 label: 'Entity With Spaces', 78 description: 'Description with spaces', 79 }); 80 }); 81 82 it('should handle long text content', async () => { 83 const longDescription = 'A'.repeat(1000); 84 85 const { data } = await createMyEntity({ 86 expectToFail: false, 87 input: { 88 name: 'longDescEntity', 89 label: 'Long Description Entity', 90 description: longDescription, 91 }, 92 }); 93 94 createdEntityId = data?.createMyEntity?.id; 95 96 expect(data.createMyEntity).toMatchObject({ 97 id: expect.any(String), 98 description: longDescription, 99 }); 100 }); 101});

Test coverage requirements:

  • ✅ Minimal required input
  • ✅ All optional fields
  • ✅ Input sanitization
  • ✅ Long text content
  • ✅ Special characters

Step 4: Update and Delete Tests

Create similar test files for update and delete operations:

Required files:

  • failing-my-entity-update.integration-spec.ts
  • successful-my-entity-update.integration-spec.ts
  • failing-my-entity-deletion.integration-spec.ts
  • successful-my-entity-deletion.integration-spec.ts

Testing Best Practices

Pattern: Cleanup

typescript
1afterEach(async () => { 2 if (createdEntityId) { 3 await deleteMyEntity({ 4 expectToFail: false, 5 input: { id: createdEntityId }, 6 }); 7 } 8});

Pattern: Type-Safe Inputs

typescript
1const input = { 2 name: 'myEntity', 3 label: 'My Entity', 4} as const satisfies CreateMyEntityInput;

Pattern: Snapshot Testing

typescript
1expectOneNotInternalServerErrorSnapshot({ 2 errors, 3});

Running Tests

bash
1# Run all entity tests 2npx jest test/integration/metadata/suites/my-entity --config=packages/twenty-server/jest.config.mjs 3 4# Run specific test file 5npx jest test/integration/metadata/suites/my-entity/failing-my-entity-creation.integration-spec.ts --config=packages/twenty-server/jest.config.mjs 6 7# Update snapshots 8npx jest test/integration/metadata/suites/my-entity --updateSnapshot --config=packages/twenty-server/jest.config.mjs

Complete Test Checklist

Test Utilities

  • create-my-entity-query-factory.util.ts created
  • create-my-entity.util.ts created
  • update-my-entity-query-factory.util.ts created
  • update-my-entity.util.ts created
  • delete-my-entity-query-factory.util.ts created
  • delete-my-entity.util.ts created

Failing Tests Coverage

  • Missing required fields
  • Empty string validation
  • Uniqueness violations
  • Standard entity protection
  • Foreign key validation
  • JSONB property validation (if applicable)

Successful Tests Coverage

  • Create with minimal input
  • Create with all optional fields
  • Input sanitization (whitespace)
  • Long text content
  • Update single field
  • Update multiple fields
  • Successful deletion

Snapshot Tests

  • All failing tests use expectOneNotInternalServerErrorSnapshot
  • Snapshots committed to __snapshots__/ directory

Success Criteria

Your integration tests are complete when:

✅ All test utilities created (minimum 6 files) ✅ Failing creation tests cover all validators ✅ Failing update tests cover business rules ✅ Failing deletion tests cover protection rules ✅ Successful tests cover all use cases ✅ All snapshots generated and committed ✅ All tests pass consistently ✅ Test coverage meets requirements (>80%)


Final Step

Step 6 Complete! → Your syncable entity is fully tested and production-ready!

Congratulations! You've successfully created a new syncable entity in Twenty's workspace migration system.

For complete workflow, see @creating-syncable-entity rule.

FAQ & Installation Steps

These questions and steps mirror the structured data on this page for better search understanding.

? Frequently Asked Questions

What is syncable-entity-testing?

Perfect for Python Analysis Agents needing advanced entity testing capabilities. Building a modern alternative to Salesforce, powered by the community.

How do I install syncable-entity-testing?

Run the command: npx killer-skills add twentyhq/twenty. It works with Cursor, Windsurf, VS Code, Claude Code, and 19+ other IDEs.

What are the use cases for syncable-entity-testing?

Key use cases include: Automating integration testing for syncable entities, Generating test cases for failing scenarios, Debugging successful use cases.

Which IDEs are compatible with syncable-entity-testing?

This skill is compatible with Cursor, Windsurf, VS Code, Trae, Claude Code, OpenClaw, Aider, Codex, OpenCode, Goose, Cline, Roo Code, Kiro, Augment Code, Continue, GitHub Copilot, Sourcegraph Cody, and Amazon Q Developer. Use the Killer-Skills CLI for universal one-command installation.

Are there any limitations for syncable-entity-testing?

Requires active database connection. Python 3.10+ only.

How To Install

  1. 1. Open your terminal

    Open the terminal or command line in your project directory.

  2. 2. Run the install command

    Run: npx killer-skills add twentyhq/twenty. The CLI will automatically detect your IDE or AI agent and configure the skill.

  3. 3. Start using the skill

    The skill is now active. Your AI agent can use syncable-entity-testing immediately in the current project.

Related Skills

Looking for an alternative to syncable-entity-testing or another community skill for your workflow? Explore these related open-source skills.

View All

widget-generator

Logo of f
f

f.k.a. Awesome ChatGPT Prompts. Share, discover, and collect prompts from the community. Free and open source — self-host for your organization with complete privacy.

149.6k
0
AI

flags

Logo of vercel
vercel

flags is a Next.js feature management skill that enables developers to efficiently add or modify framework feature flags, streamlining React application development.

138.4k
0
Browser

zustand

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
AI

data-fetching

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
AI