Open naedx opened 1 month ago
Stumbled upon this on r/aws by u/seedsseedsseeds also:
My team has been using AppSync for a couple years and for the most part, it's quite nice. Especially with JS resolvers (a pox upon VTL!) and the recently introduced AWS::Serverless::GraphqlApi type for AWS SAM, the developer experience has been greatly improved.
However, I've recently been working on improving our test suite, and have run aground upon a baffling obstacle -- @aws-appsync/utils doesn't allow for local testing!
Because the JS resolvers have a limited runtime, we're using util.nowEpochSeconds() to generate timestamps and util.dynamodb.toMapValues to marshall the dynamo commands, and the npm-installed version of the @aws-appsync/utils library has no implementation for these, only types.
I know AWS offers ways to test resolver definitions against the services itself, but these are simple resolvers, I just want a simple unit test harness to make sure the right values are defined.
Am I crazy, or missing something? Does anyone have a solution for how to test these things locally? Do I just have to waste the time to implement them myself and mock them?
They had to mock the library themselves. What is the correct solution?
I am having this issue trying to import { util } from '@aws-appsync/utils';
in a lambda function. Any update?
Hi.
Javascript resolvers run on a runtime within the AppSync service. You can call AppSync's EvaluateCode
API to test your resolver code. The @aws-appsync/utils
package contains type definitions to help you implement your code.
See details here: https://docs.aws.amazon.com/appsync/latest/devguide/test-resolvers.html
Hi @onlybakam , thanks for your reply. Does that mean that the best solution is to (1) mock the functions if you need to test locally and (2) use EvaluateCode
otherwise?
For anyone stumbling on this, you can mock the required functions in Vitest using:
// mock the required functioins from @aws-appsync/utils
vi.mock('@aws-appsync/utils', () => {
const originalAppSyncUtils = require('@aws-appsync/utils');
const { marshall } = require('@aws-sdk/util-dynamodb');
const { v4 } = require('uuid');
return {
...originalAppSyncUtils,
util: {
error: (msg: string | undefined) => { throw new Error(msg) },
autoId: () => v4(),
dynamodb: {
toMapValues: (val: any) => { return marshall(val); }
},
time: {
nowEpochSeconds: () => Math.floor(Date.now() / 1000),
nowISO8601: () => new Date().toISOString()
}
}
}
});
and you can use EvaluateCode
approach like so:
//...
describe('Online/AWS Runtime Resolver Test', async () => {
const client = new AppSync({ region: 'us-east-1' });
const runtime = { name: 'APPSYNC_JS', runtimeVersion: '1.0.0' };
const __dirname = path.resolve('amplify/data');
test('Create todo resolver', async () => {
const createTodoInput = {
"content": `Test subject ${uuidV4()}`
};
const code = fs.readFileSync(__dirname + '/features/todo/todo.create.resolver.js', 'utf8')
const contextJSON = createTestContextForEvaluate<{ input: typeof createTodoInput }>({ input: createTodoInput });
const response = await client.evaluateCode({
code,
context: JSON.stringify(contextJSON),
runtime,
function: 'request'
}).promise();
const result = JSON.parse(response.evaluationResult!);
expect(result?.key?.id?.S).toBeTypeOf('string');
expect(result?.attributeValues?.content?.S).toEqual(contextJSON.arguments.input.content);
});
});
//...
I've put a full example here https://github.com/naedx/amplify-playground/tree/dev/projects/amplify-appsync-vitest
I'm having some trouble using the
@aws-appsync/utils
(v1.8.0) in my Vitest tests. Given the following test scriptutil
is equal to{}
;Importing
Context
from@aws-appsync/utils
works as expected.I've placed a full, self contained example here.