e2e-prod: platform wallet adjust route, fund scenario player, RCs seeded directly in prod env
CI / check (push) Successful in 58s
CI / publish (push) Has been skipped

This commit is contained in:
edmand46
2026-08-20 11:35:21 +03:00
parent 322a2c0706
commit 1013f2395f
3 changed files with 23 additions and 7 deletions
+9 -4
View File
@@ -133,7 +133,8 @@ export async function runSeed(
tags: ['currency'], tags: ['currency'],
}); });
// 5. Remote configs — one per value type. // 5. Remote configs — one per value type. RCs are live per-env flags served
// straight from the outbox/cache, so they go directly into the runtime env.
const remoteConfigs: Array<{ key: string; value: string; valueType: string }> = [ const remoteConfigs: Array<{ key: string; value: string; valueType: string }> = [
{ key: 'max_energy', value: '100', valueType: 'int' }, { key: 'max_energy', value: '100', valueType: 'int' },
{ key: 'spawn_rate', value: '1.5', valueType: 'float' }, { key: 'spawn_rate', value: '1.5', valueType: 'float' },
@@ -142,9 +143,9 @@ export async function runSeed(
{ key: 'shop_layout', value: '{"cols":3}', valueType: 'json' }, { key: 'shop_layout', value: '{"cols":3}', valueType: 'json' },
]; ];
for (const rc of remoteConfigs) { for (const rc of remoteConfigs) {
await api.post(`${projPath}/remote-configs${q}`, { await api.post(`${projPath}/remote-configs${prodQ}`, {
projectId: project.id, projectId: project.id,
environment: authoringEnv, environment: runtimeEnv,
...rc, ...rc,
}); });
} }
@@ -227,7 +228,11 @@ export async function runSeed(
log(`scenario ${scenario.id} flow set`); log(`scenario ${scenario.id} flow set`);
// 11. Promote staging content to prod (the runtime serves prod/latest.json). // 11. Promote staging content to prod (the runtime serves prod/latest.json).
const release = await api.post<ReleaseResponse>(`${projPath}/releases/promote`); const release = await api.post<ReleaseResponse>(`${projPath}/releases/promote`, {
projectId: project.id,
fromEnvironment: authoringEnv,
toEnvironment: runtimeEnv,
});
await pollRelease(api, projPath, runtimeEnv, release.id, log); await pollRelease(api, projPath, runtimeEnv, release.id, log);
const prodStores = await api.get<StoreResponse[]>(`${projPath}/stores${prodQ}`); const prodStores = await api.get<StoreResponse[]>(`${projPath}/stores${prodQ}`);
+2 -2
View File
@@ -49,7 +49,7 @@ describe('e2e-prod: purchase (wallet/inventory/limits)', () => {
const offer = await resolvePaidOffer(client); const offer = await resolvePaidOffer(client);
// 1. Grant currency via the new admin endpoint. // 1. Grant currency via the new admin endpoint.
await api.post(`/game/v1/projects/${artifact.projectId}/players/${playerId}/wallet/adjust`, { await api.post(`/platform/v1/projects/${artifact.projectId}/players/${playerId}/wallet/adjust`, {
currencyCode: currency, currencyCode: currency,
amount: 1000, amount: 1000,
reason: 'e2e grant', reason: 'e2e grant',
@@ -68,7 +68,7 @@ describe('e2e-prod: purchase (wallet/inventory/limits)', () => {
// 3. Inventory credited (verified via admin player details). // 3. Inventory credited (verified via admin player details).
const details = await api.get<AdminPlayerDetails>( const details = await api.get<AdminPlayerDetails>(
`/game/v1/projects/${artifact.projectId}/players/${playerId}`, `/platform/v1/projects/${artifact.projectId}/players/${playerId}`,
); );
const inv = details.inventory?.find((i) => i.slug === artifact.item.id); const inv = details.inventory?.find((i) => i.slug === artifact.item.id);
expect(Number(inv?.amount)).toBe(artifact.store.paidGrantAmount); expect(Number(inv?.amount)).toBe(artifact.store.paidGrantAmount);
+12 -1
View File
@@ -1,5 +1,5 @@
import { describe, it, expect, beforeAll, vi } from 'vitest'; import { describe, it, expect, beforeAll, vi } from 'vitest';
import { loadArtifact, makeProdClient } from './_setup/harness.js'; import { adminApi, loadArtifact, makeProdClient } from './_setup/harness.js';
import type { SeedArtifact } from './_setup/types.js'; import type { SeedArtifact } from './_setup/types.js';
import type { NotificationEffect, StoreOfferEffect } from '../../src/index.js'; import type { NotificationEffect, StoreOfferEffect } from '../../src/index.js';
import { getScenarioRuntime } from '../../src/client/RudderClient.js'; import { getScenarioRuntime } from '../../src/client/RudderClient.js';
@@ -30,6 +30,17 @@ describe('e2e-prod: scenarios', () => {
}; };
await client.auth.loginWithDevice({ region: 'en', language: 'en' }); await client.auth.loginWithDevice({ region: 'en', language: 'en' });
// The boundary buy uses the paid offer — fund the wallet so the purchase succeeds.
const playerId = (await client.player.reload()).player!.id!;
await adminApi(artifact).post(
`/platform/v1/projects/${artifact.projectId}/players/${playerId}/wallet/adjust`,
{
currencyCode: artifact.store.paidPrice.currency,
amount: artifact.store.paidPrice.amount,
reason: 'e2e scenario funding',
},
);
// First notification dispatched. // First notification dispatched.
await vi.waitFor(() => expect(notifications.length).toBe(1), { timeout: 10_000 }); await vi.waitFor(() => expect(notifications.length).toBe(1), { timeout: 10_000 });
await notifications[0].done(); await notifications[0].done();