Code frameworks
Testando com cenários
Crie um Element, execute ações e confira cada valor e cada escrita.
O que um cenário contém
Um cenário é um arquivo JSON em scenarios/. Ele cria um Element a partir de entradas, executa ações em ordem e confere os resultados. O manifesto lista todos os arquivos de cenário, e cada arquivo contém um cenário.
{
"id": "heal-after-damage",
"framework": "keeper",
"parameters": { "name": "Mira", "max_hp": 10 },
"expectedValues": { "name": "Mira", "max_hp": 10, "hp": 10 },
"actions": [
{
"action": "hurt",
"parameters": { "amount": 6 },
"expectedWrites": [{ "op": "ledger.add", "key": "hp", "value": -6 }]
},
{
"action": "heal",
"parameters": { "amount": 9 },
"expectedWrites": [{ "op": "ledger.set", "key": "hp", "value": 10 }]
},
{ "action": "heal", "parameters": { "amount": 3 }, "expectedWrites": [] }
]
}- Linhas 4-5 Crie o Element com estas entradas e confira seus valores iniciais.
- Linha 6 actions lista os passos a executar, em ordem.
- Linha 10 As escritas exatas que o passo deve fazer.
- Linha 17 Nenhuma escrita: nada mudou.
| Campo | Significado |
|---|---|
| id | O nome do cenário. |
| framework | O id do Framework a criar. |
| parameters | As entradas usadas para criá-lo. |
| expectedValues | Todos os valores salvos logo após a construção. |
| expectedChildren | Os valores de cada espaço filho. |
| actions | Passos a executar, no máximo 32 por cenário. Cada um tem uma action, seus parameters e expectedWrites. |
| ledger | Verificações de valores derivados. |
| lists | Preenche uma lista com entradas, pelo id do preset. |
| expectedLists | As entradas que cada lista tem no final, pelo id do preset. |
| poolRolls | Rolagens registradas para um pool que usa o método roll, por id do pool. Veja Valores rolados. |
| content | Entradas de conteúdo fixadas ao Element construído (kind, entryId, name e parameters), mescladas na versão como as fixações de um personagem. |
Um passo pode usar mais campos:
| Campo do passo | Significado |
|---|---|
| choose | Para uma ação de lista: a entrada que o jogador escolhe para cada entrada ContentRef, pelo id do preset. |
| expectedRefusal | A recusa com que o passo deve terminar. O passo então espera nenhuma escrita. |
| expectedValuesAfter | Valores salvos e derivados depois do passo. Os valores derivados são recalculados primeiro. |
Escritas
expectedWrites lista todas as escritas que o passo faz, em ordem. Use ledger.set para um valor que foi definido e ledger.add para uma quantia que foi somada. Um passo que não muda nada não lista escritas, então a proteção que pula uma escrita também é testada.
Se as escritas reais forem diferentes, a verificação mostra as duas listas.
"expectedWrites": [{ "op": "ledger.set", "key": "hp", "value": 9 }]Expected ordered writes [{"op":"ledger.set","key":"hp","value":9}]; observed [{"op":"ledger.set","key":"hp","value":10}].Valores derivados e filhos
A lista ledger confere uma função de ledger. Ela informa o id da função, o valor de partida e o valor que deve ser retornado. expectedChildren confere os Elements filhos.
"expectedChildren": { "lamp": { "name": "Lantern", "oil": 5 } },- Linha 17 Confere os Elements nos espaços filhos.
"ledger": [{ "function": "guard", "currentValue": 0, "expected": 3 }]- Linha 18 Chama a função de proteção com o valor atual 0 e espera 3.
O que precisa ser coberto
- Todo constructor, ação e função de ledger precisa de um cenário.
- Toda ação precisa de pelo menos um passo. Adicione um passo para cada ramo que você quer provar, como um que escreve e um que não escreve nada.
- Uma ação que adiciona a uma lista precisa de um passo aceito e de um passo com expectedRefusal, qualquer que seja a sua oferta. O passo recusado prova que a oferta pode dizer não. Uma ação que só remove de uma lista precisa de um passo aceito.
- Os valores esperados devem ser iguais ao que o constructor realmente retorna, com as funções de ledger já aplicadas.
Os passos recebem o nome do seu cenário. Uma mensagem como heal-after-damage-2 quer dizer o terceiro passo de heal-after-damage, porque o número conta a partir de 0. Outras mensagens contam os passos a partir de 1.
Um passo que diz esperar uma recusa de uma ação que não foi recusada falha, e o contrário também:
the step expects it to be refused with NOT_OFFEREDAdd expectedRefusalUma ação sem nenhum passo falha com:
SELF_SCALAR_ACTION_SCENARIO_COVERAGE_MISSING: action keeper.hurt (Take damage) has no executable scenario steps.Uma ação de lista sem um passo aceito ou sem um passo recusado falha com:
add a step with expectedRefusal, so its refused branch is proven.add a step whose list.add is accepted, so its accepted branch is proven.Valores esperados diferentes dos que o constructor retorna falham com:
Constructor output does not match its scenario.Recusas
Uma ação de lista pode ser recusada. Um passo que espera isso nomeia o código em expectedRefusal e não lista escritas.
| Código | Quando |
|---|---|
| NOT_OFFERED | A entrada escolhida não está entre as entradas que a oferta permite. |
| ALREADY_IN_LIST | A lista já tem a entrada. |
| LIST_FULL | A lista está no tamanho máximo. |
| NOT_IN_LIST | list.remove nomeia uma entrada que a lista não tem. |
| LIST_CAP | Um limite que a lista declara seria ultrapassado. |
| SAME_NAME | A lista já tem uma entrada com esse nome. |
Este projeto prova várias delas. Ele também tem um passo em que uma proteção para a ação, então o passo espera nenhuma escrita e nenhuma recusa.
{
"id": "pack-trinkets",
"framework": "keeper",
"parameters": { "name": "Mira", "max_hp": 10 },
"expectedValues": { "name": "Mira", "max_hp": 10, "hp": 10 },
"actions": [
{
"action": "pack_trinket",
"parameters": {},
"choose": { "trinket": "rope" },
"expectedWrites": [{ "op": "list.add", "key": "pack", "value": "rope" }]
},
{
"action": "pack_trinket",
"parameters": {},
"choose": { "trinket": "rope" },
"expectedRefusal": "ALREADY_IN_LIST",
"expectedWrites": []
},
{
"action": "pack_trinket",
"parameters": {},
"choose": { "trinket": "anvil" },
"expectedRefusal": "NOT_OFFERED",
"expectedWrites": []
},
{
"action": "pack_trinket",
"parameters": {},
"choose": { "trinket": "candle" },
"expectedWrites": [
{ "op": "list.add", "key": "pack", "value": "candle" }
]
},
{
"action": "pack_trinket",
"parameters": {},
"choose": { "trinket": "bell" },
"expectedWrites": []
},
{
"action": "unpack_trinket",
"parameters": {},
"choose": { "trinket": "rope" },
"expectedWrites": [
{ "op": "list.remove", "key": "pack", "value": "rope" }
]
},
{
"action": "unpack_trinket",
"parameters": {},
"choose": { "trinket": "rope" },
"expectedRefusal": "NOT_IN_LIST",
"expectedWrites": []
}
],
"expectedLists": { "pack": ["candle"] }
}- Linhas 7-12 Aceito: list.add escreve a corda.
- Linhas 13-19 Recusado: a lista já tem a corda.
- Linhas 20-26 Recusado: a oferta não permite a bigorna.
- Linhas 35-40 A mochila já tem duas entradas, então a proteção não escreve nada e nenhuma recusa é esperada.
- Linhas 41-48 Removido: a corda sai da lista.
- Linhas 49-55 Recusado: a corda não está mais na lista.
- Linha 57 A mochila termina só com a vela.
Executando
Verificar e visualizar no The Forge compila o projeto e executa todos os cenários. Nada é publicado e nenhum personagem ao vivo muda.

