Coder Social home page Coder Social logo

bahmutov / server-logs-example Goto Github PK

View Code? Open in Web Editor NEW
7.0 1.0 1.0 727 KB

API testing using Cypress.io test runner with server-side logs

Home Page: https://glebbahmutov.com/blog/api-testing-with-sever-logs/

JavaScript 100.00%
cypress-example api-testing

server-logs-example's Introduction

server-logs-example renovate-app badge CircleCI

API testing using Cypress.io test runner with server-side logs

Shows how to use @bahmutov/cy-api plugin and its custom cy.api command to perform end-to-end API testing with full server logs. See cypress/integration/spec.js file.

Read "Black box API testing with server logs" post.

Server

Server in server/index.js adds numbers passed as query parameters.

npm start

You can test it from from another terminal using curl or httpie

$ http ':7000/?a=1&b=-10'
HTTP/1.1 200 OK
Connection: keep-alive
Date: Tue, 09 Jul 2019 01:37:13 GMT
Transfer-Encoding: chunked

-9

Server logs

Every time we call GET /, the server logs the input arguments and has several types of verbose logging. See server/index.js for entire code, but the important lines are:

// we will use console.log, util.debuglog and debug modules to log stuff
const verbose = require('util').debuglog('verbose')
const debug = require('debug')('compute')

// handle "GET /" request
const { pathname, query } = url.parse(req.url, true)
// let's just log the basic request parameters
console.log('%s %s pathname %s', req.method, req.url, pathname)
// and log the parsed query object in verbose mode
// visible when NODE_DEBUG=verbose is set
verbose('query is %o', query)
const a = parseFloat(query.a)
const b = parseFloat(query.b)
const sum = a + b
// "debug" log only shows the computation if DEBUG=compute is set
debug('%d + %d = %d', a, b, sum)

End-to-end API tests

Cypress API test

You can see request and response objects for each cy.api command and also see server-side logs, and even query into them by type and namespace. See cypress/integration/spec.js file, here is a part of the test:

it('adds numbers', function () {
  // first argument - same as "cy.request" options
  // see https://on.cypress.io/request
  // second argument - optional name for this request
  cy.api(
    {
      url: '/',
      qs: {
        a: 2,
        b: 3
      }
    },
    '2 + 3'
  ).then(({ body, messages }) => {
    // you also have 'status', 'statusText',
    // 'requestHeaders', 'headers', and 'duration'
    // we can check the value returned by the API
    expect(body, 'correct answer').to.equal('5')
    // you can also inspect messages list and make assertions against it
    const utilLogs = filter(messages, { type: 'util.debuglog' })
    const queryLog = find(utilLogs, m => /query is/.test(m.message))
    expect(queryLog)
      .property('message')
      .to.include("{ a: '2', b: '3' }")
  })
})

See more spec files in cypress/integration folder.

See

server-logs-example's People

Contributors

bahmutov avatar renovate-bot avatar renovate[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

Forkers

iqbmo04

server-logs-example's Issues

Action Required: Fix Renovate Configuration

There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.

Error type: Cannot find preset's package (github>whitesource/merge-confidence:beta)

Check on status code does not work

I want to check that the api is giving me the 500 status code back. But it does not work like below.

it('Check get licenseplace - incorrect license plate', () => {
        cy.api({ url: '/api/autoverzekering/voertuiggegevens/get?kenteken=60-TX&voertuigtype=1' }, 'Test get voertuig gegevens - incorrect license plate').then(response => {
            expect(response.status).to.eq(500);
        });
    });

I get this message back and the script stays red

CypressError: cy.request() failed on:

https://www.independer.nl/api/autoverzekering/voertuiggegevens/get?kenteken=60-TX&voertuigtype=1

The response we received from your web server was:

  > 500: Server Error

This was considered a failure because the status code was not '2xx' or '3xx'.

If you do not want status codes to cause failures pass the option: 'failOnStatusCode: false'

-----------------------------------------------------------

The request we sent was:

Method: GET
URL: https://www.independer.nl/api/autoverzekering/voertuiggegevens/get?kenteken=60-TX&voertuigtype=1
Headers: {
  "Connection": "keep-alive",
  "user-agent": "Cypress/2.1.0 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",
  "accept": "*/*",
  "cookie": "Independer.Cookies.CookieUserAuthorisation=permission=1&write-url=/api/cookieauthorisation/setcookiepermission; SSSCZ=10000=10000_0",
  "accept-encoding": "gzip, deflate"
}

-----------------------------------------------------------

The response we got was:

Status: 500 - Server Error
Headers: {
  "cache-control": "no-cache",
  "pragma": "no-cache",
  "content-type": "application/json; charset=utf-8",
  "expires": "-1",
  "server": "POWERED BY INDY",
  "set-cookie": [
    "ASP.NET_SessionId=coytc0305df42fmvriizvdyo; path=/; secure; HttpOnly; SameSite=Lax",
    "StateID=64fd7b51-ef6e-4b89-b123-53549f5f76ea; expires=Fri, 07-Jan-2022 15:40:46 GMT; path=/; HttpOnly;Secure",
    "Bron=Independer; path=/; HttpOnly;Secure"
  ],
  "x-frame-options": "DENY",
  "x-powered-by": "Hamsters",
  "x-ua-compatible": "IE=edge,chrome=1",
  "content-security-policy": "default-src https: wss: tel: 'self' 'unsafe-eval' 'unsafe-inline' data: blob:",
  "p3p": "CP=\"NOI DSP COR CURa ADMa DEVa TAIa OUR BUS IND UNI COM NAV INT\"",
  "referrer-policy": "origin",
  "strict-transport-security": "max-age=31536000",
  "x-content-type-options": "nosniff",
  "x-xss-protection": "1;mode=block",
  "content-security-policy-report-only": "default-src https: wss: 'self' 'unsafe-eval' 'unsafe-inline' data: blob:; report-uri https://92e06cc7ee8ab742c1100ba903663faa.report-uri.com/r/d/csp/reportOnly",
  "date": "Tue, 07 Jan 2020 15:40:46 GMT",
  "content-length": "5283"
}
Body: [
  {
    "key": "Message",
    "value": "An error has occurred."
  },
  {
    "key": "ExceptionMessage",
    "value": "Service operation GetVoertuiggegevens failed due to validation errors: \r\n\r\n60-TX is not a valid kenteken. \r\n"
  },
  {
    "key": "ExceptionType",
    "value": "System.ServiceModel.FaultException"
  },
  {
    "key": "StackTrace",
    "value": "   at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)\r\n   at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result)\r\n   at System.ServiceModel.Channels.ServiceChannelProxy.TaskCreator.<>c__DisplayClass7_0`1.<CreateGenericTask>b__0(IAsyncResult asyncResult)\r\n   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n   at Independer.Site.Areas.Autoverzekering.Api.VoertuiggegevensController.<Get>d__0.MoveNext() in D:\\VsTsAgent\\_work\\475\\s\\Sites\\Independer.Site\\Areas\\Autoverzekering\\Api\\VoertuiggegevensController.cs:line 15\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Threading.Tasks.TaskHelpersExtensions.<CastToObject>d__1`1.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__1.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__15.MoveNext()"
  }
]

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

npm
package.json
  • @bahmutov/all-logs 1.8.1
  • debug 4.3.6
  • @bahmutov/cy-api 1.6.2
  • cypress 3.8.3
  • cypress-plugin-snapshots 1.4.4
  • start-server-and-test 1.15.4

  • Check this box to trigger a request for Renovate to run again on this repository

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.