Este é um guia abrangente para fornecer confiabilidade em JavaScript e Node.js. Aqui são coletadas dezenas dos melhores posts, livros e ferramentas.
Primeiro, lide com métodos de teste geralmente aceitos e subjacentes a qualquer aplicativo. E então você pode se aprofundar na área de seu interesse: front-end e interfaces, back-end, IC ou todos os itens acima.
Conteúdo
Seção 0. Regra de Ouro
0. Regra de Ouro: Atenha-se aos Testes Lean
O que fazer O código de teste é diferente do que entra em operação. Torne o mais simples possível, curto, livre de abstrações, único, maravilhoso no trabalho e econômico. Outra pessoa deve olhar para o teste e entender imediatamente o que está fazendo.
Nossas cabeças estão ocupadas com o código de produção, elas não têm espaço livre para complexidade adicional. Se colocarmos uma nova parte do código complexo em nossa mente fraca, isso atrasará o trabalho de toda a equipe na tarefa, pelo que estamos testando. De fato, por causa disso, muitas equipes simplesmente evitam os testes.
Testes - é uma oportunidade de obter um assistente amigável e sorridente, com quem é muito bom trabalhar e que oferece um retorno enorme sobre pequenos investimentos. Os cientistas acreditam que em nosso cérebro existem dois sistemas: um para ações que não exigem esforço, como dirigir em uma estrada vazia, e o segundo para operações complexas que exigem consciência, como resolver equações matemáticas. Crie seus testes para o primeiro sistema, para que, ao examinar o código, tenha uma sensação de simplicidade comparável à edição de um documento HTML, e não com uma solução
2X(17 × 24)
.
Isso pode ser alcançado através da seleção cuidadosa de métodos, ferramentas e objetivos para teste, para que sejam econômicos e ofereçam um ROI grande. Teste apenas o necessário, tente ser flexível. Às vezes, vale a pena até mesmo descartar alguns testes e sacrificar a confiabilidade por uma questão de velocidade e simplicidade.

A maioria das recomendações abaixo é derivada desse princípio.
Você está pronta?Seção 1. Anatomia do teste
1.1 O nome de cada teste deve consistir em três partes
O que fazer O relatório de teste deve indicar se a revisão atual do aplicativo atende aos requisitos das pessoas que não estão familiarizadas com o código: testadores envolvidos na implantação dos engenheiros do DevOps, além de você mesmo em dois anos. Será melhor que os testes relatem informações no idioma dos requisitos e seus nomes consistam em três partes:
- O que exatamente está sendo testado? Por exemplo, o método
ProductsService.addNewProduct
. - Sob quais condições e cenários? Por exemplo, o preço não é passado para o método
- Qual é o resultado esperado? Por exemplo, um novo produto não é aprovado.
Caso contrário. A implantação falha, o teste chamado "Adicionar produto" falha. Você entende o que exatamente funciona errado?
Nota Cada capítulo tem um código de exemplo e, às vezes, uma ilustração. Veja spoilers.
Exemplos de códigoComo fazer certo. O nome do teste consiste em três partes.
1.2 Estruture os testes de acordo com o padrão AAA
O que fazer Cada teste deve consistir em três seções claramente separadas: organizar (preparação), ato (ação) e afirmar (resultado). A adesão a essa estrutura garante que o leitor do seu código não precise usar o processador cerebral para entender o plano de teste:
Organizar: todo o código que leva o sistema a um estado de acordo com o cenário de teste. Isso pode incluir a criação de uma instância do módulo no designer de teste, a adição de registros ao banco de dados, a criação de stubs em vez de objetos e qualquer outro código que prepare o sistema para a execução do teste.
Ato: execução de código como parte de um teste. Geralmente apenas uma linha.
Afirmar: verifique se o valor obtido atende às expectativas. Geralmente apenas uma linha.
Caso contrário. Você não passará apenas longas horas trabalhando com o código principal, mas seu cérebro também inchará do que deveria ser um trabalho simples - dos testes.
Exemplos de códigoComo fazer certo. Um teste estruturado de acordo com o padrão AAA.
describe.skip('Customer classifier', () => { test('When customer spent more than 500$, should be classified as premium', () => {
Um exemplo de antipadrão. Nenhuma separação, em uma única peça, é mais difícil de interpretar.
test('Should be classified as premium', () => { const customerToClassify = {spent:505, joined: new Date(), id:1} const DBStub = sinon.stub(dataAccess, "getCustomer") .reply({id:1, classification: 'regular'}); const receivedClassification = customerClassifier.classifyCustomer(customerToClassify); expect(receivedClassification).toMatch('premium'); });
1.3 Descrever as expectativas no idioma do produto: estado no estilo do BDD
O que fazer Testes de programação em estilo declarativo permitem que o usuário entenda imediatamente a essência sem gastar um único ciclo de processador cerebral. Quando você escreve um código imperativo empacotado em lógica condicional, o leitor precisa fazer muito esforço. Desse ponto de vista, é necessário descrever as expectativas em uma linguagem humana em um estilo declarativo de BDD usando expect / should e não usando código personalizado. Se em Chai e Jest não houver afirmação necessária, que é frequentemente repetida, você poderá
expandir o matcher Jest ou escrever
seu próprio plugin para o Chai .
Caso contrário. A equipe escreverá menos testes e decorará testes irritantes
with .skip()
.
Exemplos de códigoUm exemplo usando o Mocha .
Um exemplo de antipadrão. Para entender a essência do teste, o usuário é forçado a passar por um código imperativo bastante longo.
it("When asking for an admin, ensure only ordered admins in results" , ()={
Como fazer certo. A leitura deste teste declarativo é simples.
it("When asking for an admin, ensure only ordered admins in results" , ()={
1.4 Aderir ao teste de caixa preta: testar apenas métodos públicos
O que fazer Testar o interior levará a uma sobrecarga enorme e renderá quase nada. Se o seu código ou API fornecer os resultados corretos, vale a pena gastar três horas testando COMO funciona internamente e, então, oferecer suporte a esses testes frágeis? Quando você verifica o comportamento público, verifica simultaneamente implicitamente a própria implementação, seus testes falharão apenas se houver um problema específico (por exemplo, saída incorreta). Essa abordagem também é chamada de teste comportamental. Por outro lado, se você estiver testando os componentes internos (o método "caixa branca"), em vez de planejar a saída dos componentes, você se concentrará em pequenos detalhes e seus testes poderão ser interrompidos devido a pequenas alterações no código, mesmo se os resultados estiverem corretos, mas escolta terá muito mais recursos.
Caso contrário. Seus testes se comportarão como um
garoto gritando "Lobo!" : Relate em voz alta os falsos positivos (por exemplo, o teste falha devido a uma alteração no nome de uma variável privada). Não é de surpreender que em breve as pessoas comecem a ignorar as notificações de IC e um dia perderão um bug real ...
Exemplos de códigoUm exemplo de antipadrão. testando o interior sem uma boa razão.
Um exemplo usando o Mocha .
class ProductService{
1.5 Escolha a implementação simulada correta: evite objetos falsos em favor de stubs e espiões
O que fazer Implementações simuladas (duplas de teste) são um mal necessário, porque estão associadas às partes internas do aplicativo, e algumas são de grande valor (
atualize a memória de implementações imitadas: objetos falsos (zombarias), stubs (stubs) e objetos espiões (espiões) ) No entanto, nem todas as técnicas são equivalentes. Espiões e tocos são projetados para testar os requisitos, mas têm um efeito colateral inevitável - eles também afetam levemente o interior. E objetos falsos são projetados para testar o interior, o que leva a uma sobrecarga enorme, conforme descrito no capítulo 1.4.
Antes de usar implementações simuladas, faça a si mesmo a pergunta mais simples: “Eu uso isso para testar a funcionalidade que apareceu ou pode aparecer na documentação com requisitos?” Caso contrário, ele cheira a testes de caixa branca.
Por exemplo, se você quiser descobrir se o aplicativo se comporta como deveria quando o serviço de pagamento não está disponível, você pode fazer um esboço e retornar "Sem resposta" para verificar se o módulo em teste retorna o valor correto. Portanto, você pode verificar o comportamento / resposta / saída do aplicativo em certos cenários. Você também pode confirmar com a ajuda de um espião que, quando o serviço estava indisponível, a carta foi enviada, também é um teste comportamental, o que se reflete melhor na documentação com os requisitos ("Envie uma carta se as informações de pagamento não puderem ser salvas"). Ao mesmo tempo, se você criar um serviço de pagamento falso e garantir que ele seja chamado usando os tipos JS corretos, seu teste será direcionado para internos que não estão relacionados à funcionalidade do aplicativo e que provavelmente mudam com frequência.
Caso contrário. Qualquer refatoração de código envolve encontrar e atualizar todos os objetos falsos no código. Os testes de um amigo assistente se tornam um fardo.
Exemplos de códigoUm exemplo de antipadrão. Objetos falsos são para tripas.
Exemplo usando Sinon .
it("When a valid product is about to be deleted, ensure data access DAL was called once, with the right product and right config", async () => {
Como fazer certo. Os espiões são projetados para testar os requisitos, mas há um efeito colateral - eles inevitavelmente afetam o interior.
it("When a valid product is about to be deleted, ensure an email is sent", async () => {
1.6 Não use "foo", use entrada realista
O que fazer Frequentemente, erros de produção ocorrem com dados de entrada muito específicos e surpreendentes. Quanto mais realistas os dados durante o teste, maior a probabilidade de detectar erros a tempo. Para gerar dados pseudo-reais que simulam a variedade e o tipo de dados de produção, use bibliotecas especiais, por exemplo,
Faker . Essas bibliotecas podem gerar números de telefone realistas, apelidos de usuários, cartões bancários, nomes de empresas e até o texto "lorem ipsum". Você pode criar testes (além dos testes de unidade, e não em vez deles) que randomizam dados falsos para ajustar um módulo a um teste ou até importar dados reais de um ambiente de produção. Quer ir ainda mais longe? Leia o próximo capítulo (sobre testes baseados em propriedades).
Caso contrário. Seu teste de desenvolvimento terá êxito usando entradas sintéticas como "Foo", e os dados de produção poderão falhar quando um hacker
@3e2ddsf . ##' 1 fdsfds . fds432 AAAA
linha complicada como
@3e2ddsf . ##' 1 fdsfds . fds432 AAAA
@3e2ddsf . ##' 1 fdsfds . fds432 AAAA
@3e2ddsf . ##' 1 fdsfds . fds432 AAAA
.
Exemplos de códigoUm exemplo de antipadrão. Um conjunto de testes que é executado com sucesso devido ao uso de dados irrealistas.
Um exemplo usando o Jest .
const addProduct = (name, price) =>{ const productNameRegexNoSpace = /^\S*$/;
Como fazer certo. Aleatorize a entrada realista.
it("Better: When adding new valid product, get successful confirmation", async () => { const addProductResult = addProduct(faker.commerce.productName(), faker.random.number());
1.7 Use testes baseados em propriedades para validar várias combinações de entradas
O que fazer Normalmente, para cada teste, selecionamos várias amostras de dados de entrada. Mesmo que o formato de entrada seja semelhante aos dados reais (consulte o capítulo “Não use“ foo ”), abordamos apenas algumas combinações de dados de entrada (método
('', true, 1)
, método
("string" , false" , 0)
Mas, em operação, uma API chamada com cinco parâmetros pode ser chamada com milhares de combinações diferentes, uma das quais pode levar a uma
falha no processo (
distorção ) .E se você pudesse escrever um teste que envie automaticamente 1000 combinações de dados de entrada e fixação, em que combinações o código não retorna a resposta correta? A mesma coisa que fazemos com m todike teste com base nas propriedades: enviando todas as combinações possíveis de dados de entrada na unidade de teste que aumenta a chance de uma detecção de erros, por exemplo, temos um método.
addNewProduct(id, name, isDiscount)
Apoiar sua biblioteca irá chamar esse método com um número de combinações.
(, , )
, por exemplo,
(1, "iPhone", false)
,
(2, "Galaxy", true)
etc.) Você pode testar com base nas propriedades usando seu executor de teste favorito (Mocha, Jest etc.) e bibliotecas como
js-verifica ou
testcheck (possui uma documentação muito melhor). Você também pode
experimentar a biblioteca de verificação rápida , que oferece recursos adicionais e é acompanhada ativamente pelo autor.
Caso contrário. Você está escolhendo, sem pensar, dados de entrada para o teste, que abrange apenas caminhos de execução de código que funcionam bem. Infelizmente, isso reduz a eficácia dos testes como forma de detectar erros.
Exemplos de códigoComo fazer certo. Teste várias combinações com o mocha-testcheck.
require('mocha-testcheck').install(); const {expect} = require('chai'); const faker = require('faker'); describe('Product service', () => { describe('Adding new', () => {
1.8 Se necessário, use apenas fotos curtas e em linha.
O que fazer Quando você precisar
testar com base em snapshots , use apenas snapshots curtos sem todo o extra (por exemplo, em 3 a 7 linhas), incluindo-os como parte do teste (
snapshot em linha ) e não como arquivos externos. Seguir esta recomendação manterá seus testes evidentes e mais confiáveis.
Por outro lado, os guias e ferramentas do “instantâneo clássico” nos levam a armazenar arquivos grandes (por exemplo, marcação para componentes de renderização ou resultados da API JSON) em mídia externa e comparar os resultados com a versão salva sempre que o teste é executado. Pode, digamos, associar implicitamente nosso teste a 1000 linhas contendo 3000 valores que o autor do teste nunca viu sobre o que ele não esperava. Por que isso é ruim? Porque existem 1000 razões para o teste falhar. Mesmo uma linha pode invalidar um instantâneo, e isso pode acontecer com frequência. Quanto Após cada espaço, comentário ou pequena alteração no CSS ou HTML. Além disso, o nome do teste não informa sobre a falha, porque verifica apenas se 1000 linhas não foram alteradas e também incentiva o autor do teste a levar, pelo tempo que desejar, um documento longo que ele não pôde analisar e verificar. Todos esses são sintomas de um teste obscuro e apressado, que não possui uma tarefa clara e está tentando realizar demais.
É importante notar que existem várias situações em que é aceitável usar imagens longas e externas, por exemplo, ao confirmar o esquema, e não os dados (extração de valores e foco nos campos) ou quando os documentos recebidos raramente mudam.
Caso contrário. Os testes de interface do usuário falham. O código parece bom, os pixels ideais são exibidos na tela, então o que acontece? Seu teste com instantâneos acabou de revelar a diferença entre o documento original e o recém-recebido - um caractere de espaço foi adicionado à marcação ...
Exemplos de códigoUm exemplo de antipadrão. Associando um teste a algumas 2000 linhas de código desconhecidas.
it('TestJavaScript.com is renderd correctly', () => {
Como fazer certo. As expectativas são visíveis e estão no centro das atenções.
it('When visiting TestJavaScript.com home page, a menu is displayed', () => {
1.9 Evite bancos de teste globais e dados iniciais, adicione dados a cada teste separadamente
O que fazer De acordo com a regra de ouro (capítulo 0), cada teste deve adicionar e trabalhar dentro de seu próprio conjunto de linhas no banco de dados para evitar vinculações, e era mais fácil para os usuários entender o teste. Na realidade, os testadores frequentemente violam essa regra, antes de executar testes preenchendo o banco de dados com dados iniciais (sementes) (
também chamados de "banco de testes" ) para aumentar a produtividade. , (. « »), . . , , (, ).
. , , , ? , , , .
Um exemplo de antipadrão. Os testes não são independentes e usam algum tipo de gancho global para obter dados globais do banco de dados. before(() => {
Como fazer certo. Você pode permanecer dentro do teste, cada teste funciona apenas com seus próprios dados. it("When updating site name, get successful confirmation", async () => {
1.10 ,
. , - , try-catch-finally , . ( ), .
Chai:
expect(method).to.throw
( Jest:
expect(method).toThrow()
). , , . , , .
. (, CI-) , .
Um exemplo de antipadrão. Um longo caso de teste que tenta detectar um erro usando o try-catch. /it("When no product name, it throws error 400", async() => { let errorWeExceptFor = null; try { const result = await addNewProduct({name:'nest'});} catch (error) { expect(error.code).to.equal('InvalidInput'); errorWeExceptFor = error; } expect(errorWeExceptFor).not.to.be.null;
. , , , QA .
it.only("When no product name, it throws error 400", async() => { expect(addNewProduct)).to.eventually.throw(AppError).with.property('code', "InvalidInput"); });
1.11
. :
- smoke-,
- IO-less,
- , , ,
- , pull request', .
, , , #cold #api #sanity. . , Mocha :
mocha — grep 'sanity'
.
. , , , , , , , .
. '#cold-test' (Cold=== , - , ).
1.12
. , Node.js . , Node.
TDD . , , , .
-- , - . , , . , . , , , , (, ..).
. , .
2:
️2.1 :
. 10 , . . , 10 (, , ), , ,
? ?
: 2019- , TDD , , , . , , ,
. IoT-, Kafka RabbitMQ, , - . , , ? (, , ), , - .
( ) , , (« API, , !» (consumer-driven contracts)). , : , , , .
: TDD - . TDD , . , .
. ROI, Fuzz, , 10 .
. Cindy Sridharan 'Testing Microservices — the sane way'

Um exemplo:
2.2
. , . , . , , ? — . : TDD-, .
«», API, , (, , in-memory ), , , . , , « », .
. , , 20 %.
. Express API ( ).

2.3 , API
. , ( ). - , ! — , , . «
-22 » : , , .
(consumer-driven contracts) PACT : , … ! PACT — «», . PACT- — . , API CI, .
. — .
.
2.4
. , Express-. . , , , JS- {req,res}. , (,
Sinon ) {req,res}, , .
node-mock-http {req,res} . , , HTTP-, res- (. ).
. Express- === .
2.5
. . CI- , . (, ), (, ), .
Sonarqube (2600+
)
Code Climate (1500+
). ::
Keith Holliday. , .
. CodeClimate, :

2.6 , Node
. , . ( ) . , - , ? ? , API 50 % ? , Netflix - (
Chaos Engineering ). : , . , Netflix,
chaos monkey , , , , - ( Kubernetes
kube-monkey , ). , . , , Node- , , v8 1,7 , UX , ?
node-chaos (-), , Node.
. , production .
. Node-chaos , Node.js, .

2.7 ,
. ( 0), , , . , (seeds) (
« » ) . , (. « »), , . . , , (, ).
. , , , ? , , , .
. - .
before(() => {
. , .
it("When updating site name, get successful confirmation", async () => {
3:
3.1 UI
. , , , . , , ( HTML CSS) . , (, , , ), , , .
. 10 , 500 (100 = 1 ) - - .
. .
test('When users-list is flagged to show only VIP, should display only VIP members', () => {
. UI . test('When flagging to show only VIP, should display only VIP members', () => {
3.2 HTML- ,
. HTML- , . , , CSS-. , 'test-id-submit-button'. . , , .
. , , . — , , Ajax . . , CSS 'thick-border' 'thin-border'
. , .
. CSS-.
<!-- the markup code (part of React component) --> <span id="metric" className="d-flex-column">{value}</span> <!-- what if the designer changes the classs? -->
3.3
. , , . , , . , — - , (.
« » ). (, ) , .
, : , . ( ) . , .
. , . ?
. .
class Calendar extends React.Component { static defaultProps = {showFilters: false} render() { return ( <div> A filters panel with a button to hide/show filters <FiltersPanel showFilter={showFilters} title='Choose Filters'/> </div> ) } } //Examples use React & Enzyme test('Realistic approach: When clicked to show filters, filters are displayed', () => { // Arrange const wrapper = mount(<Calendar showFilters={false} />) // Act wrapper.find('button').simulate('click'); // Assert expect(wrapper.text().includes('Choose Filter')); // This is how the user will approach this element: by text })
. .
test('Shallow/mocked approach: When clicked to show filters, filters are displayed', () => {
3.4 .
. (, ). (,
setTimeOut
) , . (,
Cypress cy.request('url') ), API,
wait(expect(element)) @testing-library/DOM . , API, , . , ,
hurry-up the clock . — , , ( ). , , - npm- , ,
wait-for-expect .
. , . , . .
. E2E API (Cypress).
. , DOM- (@testing-library/dom).
. .
test('movie title appears', async () => {
3.5.
. - , . , , . :
pingdom , AWS CloudWatch
gcp StackDriver , , SLA. , , (,
lighthouse ,
pagespeed ), . — , :
,
(TTI) . , , , , , DOM, SSL . , CI, 247 CDN.
. , , , , - CDN.
. Lighthouse .

3.6 API
. ( 2), , , ( ). API (,
Sinon ,
Test doubles ), API. . API , ( ). API, . , , API . , : .
. , API 100 , 20 .
3.7 ,
. E2E (end-to-end, ) UI (. 3.6). , , . , , - . , — (, ), . - , , UI-
Cypress Pupeteer . , : 50 , , . 10 . , , , — . , .
. UI , , ( , UI) .
3.8
. , API , , . (before-all), - . , : . , . - API- . , . (, ), , , . , : , API (. 3.6).
. , 200 , 100 , 20 .
. (before-all), (before-each) (, Cypress).
Cypress .
let authenticationToken;
3.9 smoke-,
. production- , , . , , , , . smoke- . production, , , . , smoke- , .
. , , production . /Payment.
. Smoke- .
it('When doing smoke testing over all page, should load them all successfully', () => {
3.10
. , . «» , , , , . , ( ) , , -, , , . « », .
. ,
Cucumber JavaScript .
StoryBook UI- , (, , , ..) , . , , .
. , .
. cucumber-js.
. Storybook , .

3.11
. , . , . , . , - . , . , , , . , - . UI « ». , (,
wraith , PhantomCSS), . (,
Applitools ,
Perci.io ) , , « » (, ), DOM/CSS, .
. , ( ) , ?
. : , .

. wraith UI.
# Add as many domains as necessary. Key will act as a label domains: english: "http://www.mysite.com" # Type screen widths below, here are a couple of examples screen_widths: - 600 - 768 - 1024 - 1280 # Type page URL paths below, here are a couple of examples paths: about: path: /about selector: '.about' subscribe: selector: '.subscribe' path: /subscribe
4:
4.1 (~80 %),
. — , . , . — (, ), . ? , 10-30 % . 100 % , . . , : Airbus, ; , 50 % . , , 80 % (
Fowler: «in the upper 80s or 90s» ), , , .
: (CI), (
Jest ) , . , . , ( ) — . , — , , . , .
. . , , . .
.
. ( Jest).

4.2 ,
. , . , , , , . , , - , .
PricingCalculator
, , , 10 000 … , , . , . 80- , . : , , , . , - .
. , , , .
. ? , QA . : , - . , - API .

4.3
. : 100 %, . Como assim? , , , . . - : , , , .
, . JavaScript-
Stryker :
- « ». ,
newOrder.price===0
newOrder.price!=0
. «» .
- , , : , . , , .
, , , .
. , 85- 85 % .
. 100 %, 0 %.
function addNewOrder(newOrder) { logger.log(`Adding new order ${newOrder}`); DB.save(newOrder); Mailer.sendMail(newOrder.assignee, `A new order was places ${newOrder}`); return {approved: true}; } it("Test addNewOrder, don't use such test names", () => { addNewOrder({asignee: "John@mailer.com",price: 120}); });
. Stryker reports, , ().

4.4 -
. ESLint. ,
eslint-plugin-mocha , (
describe()
),
, .
eslint-plugin-jest , ( ).
. 90- , , , . , .
. , , .
describe("Too short description", () => { const userToken = userService.getDefaultToken()
5: CI
5.1 ,
. — . , . , ( !). , . (
ESLint standard Airbnb ), . ,
eslint-plugin-chai-expect , .
Eslint-plugin-promise ( ).
Eslint-plugin-security , DOS-.
eslint-plugin-you-dont-need-lodash-underscore , , V8, ,
Lodash._map(…)
.
. , , . O que está havendo? , , . . , , .
. , . , ESLint production-.

5.2
. CI , , ..? ,
. Porque : (1) -> (2) -> (3) . , , .
, , , , - .
CI- ( ,
CircleCI local CLI ) . ,
wallaby , ( ) . npm- package.json, , (, , , ). (non-zero exit code)
concurrently . — ,
npm run quality
. githook (
husky ).
. , .
. Npm-, , , .
"scripts": { "inspect:sanity-testing": "mocha **/**--test.js --grep \"sanity\"", "inspect:lint": "eslint .", "inspect:vulnerabilities": "npm audit", "inspect:license": "license-checker --failOn GPLv2", "inspect:complexity": "plato .", "inspect:all": "concurrently -c \"bgBlue.bold,bgMagenta.bold,yellow\" \"npm:inspect:quick-testing\" \"npm:inspect:lint\" \"npm:inspect:vulnerabilities\" \"npm:inspect:license\"" }, "husky": { "hooks": { "precommit": "npm run inspect:all", "prepush": "npm run inspect:all" } }
5.3 production-
. — CI-. . —
Docker-compose . (, ) production-.
AWS Local AWS-.
, serverless
AWS SAM Faas-.
Kubernetes CI-, . , « Kubernetes»
Minikube MicroK8s , , . « Kubernetes»: CI- (,
Codefresh ) Kubernetes-, CI- ; .
. .
: CI-, Kubernetes-
(Dynamic-environments Kubernetes )
deploy: stage: deploy image: registry.gitlab.com/gitlab-examples/kubernetes-deploy script: - ./configureCluster.sh $KUBE_CA_PEM_FILE $KUBE_URL $KUBE_TOKEN - kubectl create ns $NAMESPACE - kubectl create secret -n $NAMESPACE docker-registry gitlab-registry --docker-server="$CI_REGISTRY" --docker-username="$CI_REGISTRY_USER" --docker-password="$CI_REGISTRY_PASSWORD" --docker-email="$GITLAB_USER_EMAIL" - mkdir .generated - echo "$CI_BUILD_REF_NAME-$CI_BUILD_REF" - sed -e "s/TAG/$CI_BUILD_REF_NAME-$CI_BUILD_REF/g" templates/deals.yaml | tee ".generated/deals.yaml" - kubectl apply --namespace $NAMESPACE -f .generated/deals.yaml - kubectl apply --namespace $NAMESPACE -f templates/my-sock-shop.yaml environment: name: test-for-ci
5.4
. , , . , 500 , , . , CI- (
Jest ,
AVA Mocha ) , . CI- (!), . , CLI , , .
. — , .
5.5
. , . 10 ? CI- npm-
license check plagiarism check ( ), , , Stackoveflow .
. , , .
.

5.6
. , Express, .
npm audit ,
snyk ( ). CI .
. . .
: NPM Audit

5.7
. package-lock.json Yarn npm ( ): .
npm install
npm update
, . , — . , package.json
ncu .
, . :
- CI , , npm outdated npm-check-updates (ncu). .
- , pull request' .
: ? , ( ,
eslint-scope ). « »:
latest , , (, 1.3.1, — 1.3.8).
. , .
5.8 CI-, Node
. , Node . , Node.
- . , Jenkins .
- Docker.
- , . . smoke-, (, , ) .
- , , , , , .
- , . , -. - ( ).
- . .
- , , .
- (, Docker-).
- , .
node_modules
.
. , .
5.9 : CI-, Node
. , , . Node, CI . , MySQL, Postgres. CI- «», MySQl, Postgres Node. , - (, ). CI, , .
. - ?
: Travis ( CI) Node.
language: node_js node_js: - "7" - "6" - "5" - "4" install: - npm install script: - npm run test