taimos / ask-sdk-test

Alexa Skill Test Framework for Typescript and ASK2
MIT License
21 stars 12 forks source link

DynamoDB: Could not read item from table #5

Closed patrickbussmann closed 5 years ago

patrickbussmann commented 5 years ago

Description

I tried my skill with DynamoDB implementation. But it didn't worked like your example.

returns the correct responses:

expected 'An error occured. Could not read item (amzn1.ask.account.VOID) from table (AlexaSkill)
+ expected - actual

-An error occured. Could not read item (amzn1.ask.account.VOID) from table (AlexaSkill): expected { id: 'amzn1.ask.account.VOID' } to have a property 'userId'
+Example

Steps to Reproduce

skill.spec.ts

import {AlexaTest, LaunchRequestBuilder, SkillSettings} from 'ask-sdk-test';
import {handler as skillHandler} from '../src/index';

const skillSettings: SkillSettings = {
    appId: 'amzn1.ask.skill.00000000-0000-0000-0000-000000000000',
    userId: 'amzn1.ask.account.VOID',
    deviceId: 'amzn1.ask.device.VOID',
    locale: 'de-DE',
};

const alexaTest = new AlexaTest(skillHandler, skillSettings).withDynamoDBPersistence('AlexaSkill', 'userId', 'mapAttr');

describe('LaunchRequest', () => {
    alexaTest.test([
        {
            request: new LaunchRequestBuilder(skillSettings).build(),
            says: 'Please ask for something?',
            repromptsNothing: false,
            shouldEndSession: false,
        },
    ]);
});

index.ts

export let handler = SkillBuilders.standard()
    .addRequestHandlers(
        new LaunchRequestHandler()
    )
    .addResponseInterceptors(
        new PersistenceSavingResponseInterceptor()
    )
    .addErrorHandlers(new CustomErrorHandler())
    .withTableName('AlexaSkill')
    // .withAutoCreateTable(true)
    .lambda();

LaunchRequestHandler.ts Similar to example.

public async handle(handlerInput : HandlerInput) : Promise<Response> {
    const attributes = await handlerInput.attributesManager.getPersistentAttributes();
    attributes.foo = 'bar';
    attributes.count = 1;
    handlerInput.attributesManager.setPersistentAttributes(attributes);
    await handlerInput.attributesManager.savePersistentAttributes();

    return handlerInput.responseBuilder.speak('Hello World!').getResponse();
}

But I do it with a small saving interceptor.

export class PersistenceSavingResponseInterceptor implements ResponseInterceptor {
    process(handlerInput: HandlerInput): Promise<void> {
        return handlerInput.attributesManager.savePersistentAttributes();
    }
}

Expected behavior:

No error occurs. The mockup have an empty object for the user or something similar.

Actual behavior:

An error occurs.

Handling IntentRequest with name OrderItIntent
{ AskSdk.DynamoDbPersistenceAdapter Error: Could not read item (amzn1.ask.account.VOID) from table (AlexaSkill): expected { id: 'amzn1.ask.account.VOID' } to have a property 'userId'
    at Object.createAskSdkError (C:\alexa\skill\node_modules\ask-sdk-runtime\lib\util\AskSdkUtils.ts:23:19)
    at DynamoDbPersistenceAdapter.<anonymous> (C:\alexa\skill\node_modules\ask-sdk-dynamodb-persistence-adapter\lib\attributes\persistence\DynamoDbPersistenceAdapter.ts:104:19)
    at step (C:\alexa\skill\node_modules\ask-sdk-dynamodb-persistence-adapter\dist\attributes\persistence\DynamoDbPersistenceAdapter.js:44:23)
    at Object.next (C:\alexa\skill\node_modules\ask-sdk-dynamodb-persistence-adapter\dist\attributes\persistence\DynamoDbPersistenceAdapter.js:25:53)
    at C:\alexa\skill\node_modules\ask-sdk-dynamodb-persistence-adapter\dist\attributes\persistence\DynamoDbPersistenceAdapter.js:19:71
    at new Promise (<anonymous>)

Environment

NodeJS-Version: v11.3.0

TypeScript-Version: 6.5.0

OS: Windows 10 Pro x64

hoegertn commented 5 years ago

If you use the standard DynamoDB persistence the keys are named id and attributes, so you have to specify withDynamoDBPersistence('AlexaSkill', 'id', 'attributes');.

In the example, I am remapping the names to match the ones from the SDK v1.

hoegertn commented 5 years ago

But thanks for the issue. I checked and indeed the defaults the tester uses were wrong too.

hoegertn commented 5 years ago

Fixed in 2.0.4

patrickbussmann commented 5 years ago

Ah ok. Thank you @hoegertn.

This testing isn't compatible with permissions, isn't it? Because I get this error:

Cannot read property 'scopes' of undefined

When I try the Amazon Pay example. (https://developer.amazon.com/de/docs/amazon-pay/integrate-skill-with-amazon-pay-v2.html#check-for-amazon-pay-permissions-and-voice-purchase-settings)

const permissions = handlerInput.requestEnvelope.context.System.user.permissions;
const amazonPayPermission = permissions.scopes['payments:autopay_consent'];
if (amazonPayPermission.status === "DENIED") {
    return handlerInput.responseBuilder
        .speak('Please enable permission for Amazon Pay in your companion app.')
        .withAskForPermissionsConsentCard(['payments:autopay_consent'])
        .getResponse();
}

For myself I will check if it's not undefined now. But maybe it is interesting for the future to test also this cases. If the user have permissions or not. Testing payment workflows, too. Or all things we can do with ASK SDK v2 👍

But this topic is closed now. Thank's for your answer. This is the final and working solution.

const alexaTest = new AlexaTest(skillHandler, skillSettings).withDynamoDBPersistence('AlexaSkill', 'id', 'attributes');