Token导航 LogoToken导航

Agent Skill · 待分类

syncable-entity-testing(可同步实体测试)

用于辅助测试设计、自动化测试、用例整理和回归验证。它适合让 Agent 编写单元测试、端到端测试、测试计划或根据失败日志定位问题。使用时需要确认项目测试框架、运行命令和夹具数据,避免为了通过测试而改坏真实逻辑;涉及浏览器或外部服务时,应区分本地模拟、测试环境和生产环境。

syncable-entity-testing 是待分类类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为需要联网;许可证信息还不明确,第三方扫描已通过,按安装量在待分类类的 11,209 个 Skill 里排第 3,826。

总安装 888周安装 37GitHub Stars 43,468下载 296核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:syncable-entity-testing(可同步实体测试)
来源仓库:https://github.com/twentyhq/twenty
仓库路径:skills/syncable-entity-testing
安装命令:
npx skills add https://github.com/twentyhq/twenty --skill syncable-entity-testing
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/twentyhq/twenty --skill syncable-entity-testing

这个 Skill 是做什么的

这个 Skill 的分类还没最终确定,用法以来源仓库的说明为准。

辅助测试用例设计与回归验证,支持单元测试生成与缺陷定位。适合在 Codex、Claude、Cursor、Gemini CLI 中提升代码质量时使用。通过 GitHub 仓库安装,使用 npx 命令添加技能并指定路径。需结合项目实际框架选择测试工具,避免引入不兼容依赖。

执行测试前应备份关键数据,防止测试过程破坏原始业务逻辑。

来源仓库内路径:skills/syncable-entity-testing

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/twentyhq/twenty --skill syncable-entity-testin…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要需要联网,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

syncable-entity-testing 怎么安装?

在终端执行 npx skills add https://github.com/twentyhq/twenty --skill syncable-entity-testing。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

syncable-entity-testing 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

syncable-entity-testing 需要什么权限?

权限级别是需要联网。该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

syncable-entity-testing 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

syncable-entity-testing 用的人多吗?

公开数据是累计安装 888 次,近一周安装 37 次,下载 296 次,GitHub 43,468 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

syncable-entity-testing 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 第三方扫描已通过,常见的高风险行为没有命中。
  • 来源仓库有 43,468 星,维护活跃度相对可查。

先想清楚的地方

  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理待分类类任务、又不想每次都手写提示词的人。

不太适合

  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

待分类类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
infsh-cli

infsh CLI · Codex、Claude

4,374,576382权限未标注未明确未收录
ai-video-generation

AI 视频生成 · Codex、Claude

4,313,376382调用外部服务未明确有提醒
lark-openapi-explorer

云雀 OpenAPI 浏览器 · Codex、Claude

2,064,1209,011需要联网未明确有提醒
lark-workflow-standup-report

Lark 工作流程站立报告 · Codex、Claude

2,041,6328,978需要联网未明确通过
use-my-browser

使用我的浏览器 · Codex、Claude

1,848,49140操作浏览器未明确未通过
syncable-entity-testing

可同步实体测试 · 本页

88843,468需要联网未明确通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

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

import gql from 'graphql-tag';
import { type PerformMetadataQueryParams } from 'test/integration/metadata/types/perform-metadata-query.type';
import { type CreateMyEntityInput } from 'src/engine/metadata-modules/my-entity/dtos/create-my-entity.input';

export type CreateMyEntityFactoryInput = CreateMyEntityInput;

const DEFAULT_MY_ENTITY_GQL_FIELDS = `
  id
  name
  label
  description
  isCustom
  createdAt
  updatedAt
`;

export const createMyEntityQueryFactory = ({
  input,
  gqlFields = DEFAULT_MY_ENTITY_GQL_FIELDS,
}: PerformMetadataQueryParams<CreateMyEntityFactoryInput>) => ({
  query: gql`
    mutation CreateMyEntity($input: CreateMyEntityInput!) {
      createMyEntity(input: $input) {
        ${gqlFields}
      }
    }
  `,
  variables: {
    input,
  },
});

Pattern: Wrapper Utility

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

import {
  type CreateMyEntityFactoryInput,
  createMyEntityQueryFactory,
} from 'test/integration/metadata/suites/my-entity/utils/create-my-entity-query-factory.util';
import { makeMetadataAPIRequest } from 'test/integration/metadata/suites/utils/make-metadata-api-request.util';
import { type CommonResponseBody } from 'test/integration/metadata/types/common-response-body.type';
import { type PerformMetadataQueryParams } from 'test/integration/metadata/types/perform-metadata-query.type';
import { warnIfErrorButNotExpectedToFail } from 'test/integration/metadata/utils/warn-if-error-but-not-expected-to-fail.util';
import { warnIfNoErrorButExpectedToFail } from 'test/integration/metadata/utils/warn-if-no-error-but-expected-to-fail.util';
import { type MyEntityDto } from 'src/engine/metadata-modules/my-entity/dtos/my-entity.dto';

export const createMyEntity = async ({
  input,
  gqlFields,
  expectToFail = false,
  token,
}: PerformMetadataQueryParams<CreateMyEntityFactoryInput>): CommonResponseBody<{
  createMyEntity: MyEntityDto;
}> => {
  const graphqlOperation = createMyEntityQueryFactory({
    input,
    gqlFields,
  });

  const response = await makeMetadataAPIRequest(graphqlOperation, token);

  if (expectToFail === true) {
    warnIfNoErrorButExpectedToFail({
      response,
      errorMessage: 'My entity creation should have failed but did not',
    });
  }

  if (expectToFail === false) {
    warnIfErrorButNotExpectedToFail({
      response,
      errorMessage: 'My entity creation has failed but should not',
    });
  }

  return { data: response.body.data, errors: response.body.errors };
};

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

import { expectOneNotInternalServerErrorSnapshot } from 'test/integration/graphql/utils/expect-one-not-internal-server-error-snapshot.util';
import { createMyEntity } from 'test/integration/metadata/suites/my-entity/utils/create-my-entity.util';
import { deleteMyEntity } from 'test/integration/metadata/suites/my-entity/utils/delete-my-entity.util';
import {
  eachTestingContextFilter,
  type EachTestingContext,
} from 'twenty-shared/testing';
import { isDefined } from 'twenty-shared/utils';
import { type CreateMyEntityInput } from 'src/engine/metadata-modules/my-entity/dtos/create-my-entity.input';

type TestContext = {
  input: CreateMyEntityInput;
};

type GlobalTestContext = {
  existingEntityLabel: string;
  existingEntityName: string;
};

const globalTestContext: GlobalTestContext = {
  existingEntityLabel: 'Existing Test Entity',
  existingEntityName: 'existingTestEntity',
};

type CreateMyEntityTestingContext = EachTestingContext<TestContext>[];

describe('My entity creation should fail', () => {
  let existingEntityId: string | undefined;

  beforeAll(async () => {
    // Setup: Create entity for uniqueness tests
    const { data } = await createMyEntity({
      expectToFail: false,
      input: {
        name: globalTestContext.existingEntityName,
        label: globalTestContext.existingEntityLabel,
      },
    });

    existingEntityId = data.createMyEntity.id;
  });

  afterAll(async () => {
    // Cleanup
    if (isDefined(existingEntityId)) {
      await deleteMyEntity({
        expectToFail: false,
        input: { id: existingEntityId },
      });
    }
  });

  const failingMyEntityCreationTestCases: CreateMyEntityTestingContext = [
    // Input transpilation validation
    {
      title: 'when name is missing',
      context: {
        input: {
          label: 'Entity Missing Name',
        } as CreateMyEntityInput,
      },
    },
    {
      title: 'when label is missing',
      context: {
        input: {
          name: 'entityMissingLabel',
        } as CreateMyEntityInput,
      },
    },
    {
      title: 'when name is empty string',
      context: {
        input: {
          name: '',
          label: 'Empty Name Entity',
        },
      },
    },

    // Validator business logic
    {
      title: 'when name already exists (uniqueness)',
      context: {
        input: {
          name: globalTestContext.existingEntityName,
          label: 'Duplicate Name Entity',
        },
      },
    },
    {
      title: 'when trying to create standard entity',
      context: {
        input: {
          name: 'myEntity',
          label: 'Standard Entity',
          isCustom: false,
        } as CreateMyEntityInput,
      },
    },

    // Foreign key validation
    {
      title: 'when parentEntityId does not exist',
      context: {
        input: {
          name: 'invalidParentEntity',
          label: 'Invalid Parent Entity',
          parentEntityId: '00000000-0000-0000-0000-000000000000',
        },
      },
    },
  ];

  it.each(eachTestingContextFilter(failingMyEntityCreationTestCases))(
    '$title',
    async ({ context }) => {
      const { errors } = await createMyEntity({
        expectToFail: true,
        input: context.input,
      });

      expectOneNotInternalServerErrorSnapshot({
        errors,
      });
    },
  );
});

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

import { createMyEntity } from 'test/integration/metadata/suites/my-entity/utils/create-my-entity.util';
import { deleteMyEntity } from 'test/integration/metadata/suites/my-entity/utils/delete-my-entity.util';
import { type CreateMyEntityInput } from 'src/engine/metadata-modules/my-entity/dtos/create-my-entity.input';

describe('My entity creation should succeed', () => {
  let createdEntityId: string;

  afterEach(async () => {
    if (createdEntityId) {
      await deleteMyEntity({
        expectToFail: false,
        input: { id: createdEntityId },
      });
    }
  });

  it('should create entity with minimal required input', async () => {
    const { data } = await createMyEntity({
      expectToFail: false,
      input: {
        name: 'minimalEntity',
        label: 'Minimal Entity',
      },
    });

    createdEntityId = data?.createMyEntity?.id;

    expect(data.createMyEntity).toMatchObject({
      id: expect.any(String),
      name: 'minimalEntity',
      label: 'Minimal Entity',
      description: null,
      isCustom: true,
      createdAt: expect.any(String),
      updatedAt: expect.any(String),
    });
  });

  it('should create entity with all optional fields', async () => {
    const input = {
      name: 'fullEntity',
      label: 'Full Entity',
      description: 'Entity with all fields specified',
    } as const satisfies CreateMyEntityInput;

    const { data } = await createMyEntity({
      expectToFail: false,
      input,
    });

    createdEntityId = data?.createMyEntity?.id;

    expect(data.createMyEntity).toMatchObject({
      id: expect.any(String),
      name: 'fullEntity',
      label: 'Full Entity',
      description: 'Entity with all fields specified',
      isCustom: true,
    });
  });

  it('should sanitize input by trimming whitespace', async () => {
    const { data } = await createMyEntity({
      expectToFail: false,
      input: {
        name: '  entityWithSpaces  ',
        label: '  Entity With Spaces  ',
        description: '  Description with spaces  ',
      },
    });

    createdEntityId = data?.createMyEntity?.id;

    expect(data.createMyEntity).toMatchObject({
      id: expect.any(String),
      name: 'entityWithSpaces',
      label: 'Entity With Spaces',
      description: 'Description with spaces',
    });
  });

  it('should handle long text content', async () => {
    const longDescription = 'A'.repeat(1000);

    const { data } = await createMyEntity({
      expectToFail: false,
      input: {
        name: 'longDescEntity',
        label: 'Long Description Entity',
        description: longDescription,
      },
    });

    createdEntityId = data?.createMyEntity?.id;

    expect(data.createMyEntity).toMatchObject({
      id: expect.any(String),
      description: longDescription,
    });
  });
});

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

afterEach(async () => {
  if (createdEntityId) {
    await deleteMyEntity({
      expectToFail: false,
      input: { id: createdEntityId },
    });
  }
});

Pattern: Type-Safe Inputs

const input = {
  name: 'myEntity',
  label: 'My Entity',
} as const satisfies CreateMyEntityInput;

Pattern: Snapshot Testing

expectOneNotInternalServerErrorSnapshot({
  errors,
});

Running Tests

# Run all entity tests
npx jest test/integration/metadata/suites/my-entity --config=packages/twenty-server/jest.config.mjs

# Run specific test file
npx jest test/integration/metadata/suites/my-entity/failing-my-entity-creation.integration-spec.ts --config=packages/twenty-server/jest.config.mjs

# Update snapshots
npx 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.

平台分布

Codex

35.95%
按下载量换算106

Claude

32.47%
按下载量换算96

Cursor

16.88%
按下载量换算50

Gemini CLI

9.97%
按下载量换算30

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills