This commit is contained in:
2026-09-02 09:19:43 +03:00
parent 74cb5b6176
commit 962f489142
34 changed files with 1190 additions and 124 deletions
@@ -0,0 +1,71 @@
import { test } from '@japa/runner'
import { join } from 'node:path'
import { renderTemplate } from '#services/module_generator/writers/template_renderer'
const TEMPLATE_DIR = join(process.cwd(), 'app', 'templates', 'backend')
const API_TEMPLATE_DIR = join(TEMPLATE_DIR, 'api')
const context = {
name: 'widget',
capName: 'Widget',
moduleName: 'Widget',
modelName: 'Widgets',
pascalCaseName: 'Widget',
snakeCaseName: 'widget',
snake: 'widget',
swaggerExample: '{ "id": 42, "name": "Example widget" }',
createFields: [{ column_name: 'name', sampleValue: "'Example widget'" }],
updateFields: [{ column_name: 'name', sampleValue: "'Updated widget'" }],
}
test.group('ERP module generator templates', () => {
test('generates authenticated, permission-authorized API CRUD routes', ({ assert }) => {
const routes = renderTemplate(join(API_TEMPLATE_DIR, 'routes.hbs'), context)
const controller = renderTemplate(join(API_TEMPLATE_DIR, 'controller.hbs'), context)
assert.include(routes, "import { middleware } from '#start/kernel'")
assert.include(routes, '.use([middleware.auth()])')
assert.include(controller, "import WidgetPolicy from '#modules/Widget/policy/widget_policy'")
assert.include(controller, "authorize('viewWidgetList')")
assert.include(controller, "authorize('viewWidget')")
assert.include(controller, "authorize('createWidget')")
assert.include(controller, "authorize('updateWidget')")
assert.include(controller, "authorize('deleteWidget')")
})
test('generates concrete AutoSwagger examples for every API response status', ({ assert }) => {
const controller = renderTemplate(join(API_TEMPLATE_DIR, 'controller.hbs'), context)
assert.include(controller, '@responseBody 200 - [{ "id": 42, "name": "Example widget" }]')
assert.include(controller, '@responseBody 201 - { "id": 42, "name": "Example widget" }')
assert.include(controller, '@responseBody 401 - { "message": "Unauthorized" }')
assert.include(controller, '@responseBody 403 - { "message": "Forbidden" }')
assert.include(
controller,
'@responseBody 422 - { "errors": [{ "message": "Validation failed", "rule": "required", "field": "name" }] }'
)
assert.notInclude(controller, '<Error422>')
})
test('generates API specs covering every CRUD endpoint plus auth and permission boundaries', ({
assert,
}) => {
const spec = renderTemplate(join(TEMPLATE_DIR, 'tests', 'api.spec.hbs'), context)
for (const methodAndPath of [
'GET /api/widget -> list',
'POST /api/widget -> create',
'GET /api/widget/:id -> show',
'PUT /api/widget/:id -> update',
'DELETE /api/widget/:id -> destroy',
]) {
assert.include(spec, methodAndPath)
}
assert.include(spec, 'rejects unauthenticated requests')
assert.include(spec, 'rejects a token without the required permission')
assert.include(spec, 'assertStatus(401)')
assert.include(spec, 'assertStatus(403)')
assert.include(spec, 'assertStatus(404)')
})
})
@@ -0,0 +1,23 @@
import { test } from '@japa/runner'
import testUtils from '@adonisjs/core/services/test_utils'
import Tenant from '#base_modules/Tenant/model/tenant'
import TenantAccessService from '#base_modules/Tenant/services/tenant_access_service'
import { createAdminWithToken } from '#tests/utils/auth'
test.group('TenantAccessService', (group) => {
group.each.setup(() => testUtils.db().wrapInGlobalTransaction())
test('resolves an active tenant for a member admin', async ({ assert }) => {
const { admin } = await createAdminWithToken([])
const tenant = await Tenant.create({
name: 'Service GmbH',
slug: 'service-gmbh',
status: 'active',
})
await tenant.related('admins').attach([admin.id])
const resolved = await new TenantAccessService().resolveForAdmin(admin.id, tenant.id)
assert.deepEqual(resolved, { id: tenant.id, name: tenant.name, slug: tenant.slug })
})
})