Aplicar regras e validar seu modelo
Às vezes você pode querer aplicar regras personalizadas ao seu modelo ou validar sua consistência. Aqui vai uma receita simples de como fazer isso.
Testar seu modelo
Seção intitulada “Testar seu modelo”Neste exemplo, vamos usar o Vitest junto com a API do LikeC4. A API do LikeC4 oferece métodos para consultar e percorrer o modelo, perfeita para escrever testes que reforçam suas regras.
npm i likec4 vitestpnpm add likec4 vitestyarn add likec4 vitestbun add likec4 vitestExemplo
Seção intitulada “Exemplo”Suponha que queremos exigir que todo elemento do tipo app tenha uma technology especificada.
import { LikeC4 } from 'likec4'import { test } from 'vitest'
// Initialize and compute LikeC4 Modelconst likec4 = await LikeC4.fromWorkspace('..')const model = await likec4.computedModel()
// With `test.for` we generate tests for each element of kind `app`// This improves the output, showing each test failure separatelytest.for( model // Select elements of kind `app` .elementsWhere({ kind: 'app' }) // Map to array of [id, element] tuples, we need it for test names .map(e => [e.id, e] as const) .toArray(),)('app "%s" has technology', ([, e], { expect }) => { expect(e.technology).toBeTruthy()})
// Or we can use `expect.soft` to accumulate all errorstest('elements of kind `app` have technology', ({ expect }) => { expect.hasAssertions() for (const app of model.elements()) { if (app.kind !== 'app') continue // Skip non-app elements expect.soft(app.technology, `app ${app.id} has no technology`).toBeTruthy() }})Pré-gerar o modelo
Seção intitulada “Pré-gerar o modelo”Podemos otimizar nossos testes pré-gerando o modelo no global setup:
import { execSync } from 'node:child_process'
export default function() { execSync('npx likec4 gen model -o ./test/likec4-model.ts', { stdio: 'inherit' })}O modelo gerado é totalmente tipado, oferecendo verificação de tipos e autocompletar nos testes:
import { likec4model } from './likec4-model'import { test } from 'vitest'
test('Relationships should have metadata', ({ expect }) => { expect.hasAssertions() for (const r of likec4model.relationships()) { expect.soft( r.getMetadata('key'), // here we get type checking `Relationship ${r.source.id} -> ${r.target.id} has no metadata` ).toBeDefined() }})Podemos ir além e usar o contexto de teste para melhorar nossa experiência:
import { likec4model } from './likec4-model'import { test } from 'vitest'
interface LikeC4TestFixtures { likec4: typeof likec4model}
// This wil be our test function with the model in the contextexport const likec4test = test.extend<LikeC4TestFixtures>({ likec4: async ({}, use) => { await use(likec4model) },})Agora refatore os testes para usá-la:
import { likec4test } from './likec4test'
likec4test('Relationships should have metadata', ({ expect, likec4 }) => { expect.hasAssertions() for (const r of likec4.relationships()) { expect.soft( r.getMetadata('key'), // here we get type checking `Relationship ${r.source.id} -> ${r.target.id} has no metadata` ).toBeDefined() }})Conclusão
Seção intitulada “Conclusão”Essa abordagem facilita aplicar restrições personalizadas e validar a consistência do seu modelo. Executar essas verificações no pipeline de CI é rápido e fornece feedback imediato quando o modelo quebra suas regras.