Debug

like a detective

Mariam reba Alexander

Software Engineer

web

security

 Maersk.com - Logistics HUB

LivES in Denmark

KERALA, SOUTH INDIA

MYSTERIES

INVESTIGATion

Looking for clues 

What Clue do you look for ?

console errors

USUal suspects

  • TypeError / Reference Error
  • Script error
  • Syntax Error: JSON.parse
  • Network error

Uncaught TypeError: Cannot read properties of undefined (chrome)

REal WORLd EXAMPLE

REal WORLd EXAMPLE

REal WORLd EXAMPLE

Typerror: undefined/null is not an object (safari)

FIX

//define testarray

const test = [];

//check defined

if(test){
 console.log(test.length === 0);
}

//OR

console.log(test?.length === 0);

script error

code

<!DOCTYPE html>
<html lang="">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <meta http-equiv="Content-Security-Policy" content="script-src 'self'">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.min.js"></script>
    <title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>

FIX 1

<!DOCTYPE html>
<html lang="">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <meta http-equiv="Content-Security-Policy" content="script-src 'self' https://cdn.jsdelivr.net/npm/bootstrap@5.1.3">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.min.js" crossorigin="anonymous"></script>
    <title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>

FIX 2

//set a Cross Origin HTTP header server side

Acess-Control-Allow-Origin: *

//Example for Node js

// Add headers before the routes are defined
app.use(function (req, res, next) {

    // domain you want to allow 
    res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8000');

    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
    res.setHeader('Access-Control-Allow-Credentials', true);
    next();
});

//OR specify multiple domains 
app.use((req, res, next) => {
  const allowedOrigins = ['http://127.0.0.1:8020', 'http://localhost:8020', 'http://127.0.0.1:9000', 'http://localhost:9000'];
  const origin = req.headers.origin;
  if (allowedOrigins.includes(origin)) {
       res.setHeader('Access-Control-Allow-Origin', origin);
  }
  //res.header('Access-Control-Allow-Origin', 'http://127.0.0.1:8020');
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
    res.setHeader('Access-Control-Allow-Credentials', true);
    next();
});

SyntaxError: JSON.parse: bad parsing

Parsing invalid json

Property names must be double-quoted strings

No trailing commas

Look for clues

  • Console errors
    • Examples: Typerror, Script error, Syntax error

2. collect witness statements

Cross-checking

  • Compare cross-browser
  • Compare with another system
  • Comparing commits

usual suspects

  • Polyfills/fallbacks missing for unsupported browser feature
  • Git branch behind commits - git pull
  • Package not updated - npm install
  • Browser cache - Empty cache and reload
  • Network request
  • Token expiry

3. Narrow down suspect list

devtools

$0- $4 (console utilities API)

Break points

conditional Break points

watch

Live expressions

Code

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <p>Here is a suggestion on what you can do</p>
    <h3>{{ response.data.activity }}</h3>
    <p>Type: {{ response.data.type }}</p>
    <button class="button-pink" role="button" @click="getSuggestion">
      Suggest me again
    </button>
  </div>
</template>

<script>
import axios from "axios";
export default {
  name: 'Debug',
  props: {
    msg: String
  },
  data() {
    return {
      response: {}
    }
  },
  mounted(){
    this.getSuggestion();
  },
  methods: {
    async getSuggestion() {
      try {
        this.response = await axios.get('https://www.boredapi.com/api/activity');
      } catch (error) {
        console.error(error);
      }
    }
  }
}
</script>

FIX

<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
    <p>Here is a suggestion on what you can do</p>
    <template v-if="response.data">
      <h3>{{ response.data.activity }}</h3>
      <p>Type: {{ response.data.type }}</p>
    </template>
    <button class="button-pink" role="button" @click="getSuggestion">
      Suggest me again
    </button>
  </div>
</template>

<script>
import axios from "axios";
export default {
  name: 'Debug',
  props: {
    msg: String
  },
  data() {
    return {
      response: {}
    }
  },
  mounted(){
    this.getSuggestion();
  },
  methods: {
    async getSuggestion() {
      try {
        this.response = await axios.get('https://www.boredapi.com/api/activity');
      } catch (error) {
        console.error(error);
      }
    }
  }
}
</script>

working app

Monitor window events

monitorevents($0)

network Block url

save request as har 

copy as curl

devtools extensions

angular devtools

React developer tools

vue devtools

git

Git diff / compare

Git blame

#show last author of each line of file
git blame src/script.js

#show last author of specified line
git blame src/script.js -L 28,29

#show moved or copied lines within
# the same file (original author)
git blame -M src/script.js


#shows lines that were moved or 
#copied from other files (original author)
git blame -C src/script.js

Git Bisect

4. an associate can come in handy

5.capturing

Error handling & tests

//ERROR HANDLING

try {
  doSomething();
} catch (e) {              
  console.log(e);
}
//UNIT TESTS

const sum = require('./sum');

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});
//E2E TESTS 

describe('My e2e Test', () => {
  it('Gets, types and asserts', () => {
    cy.visit('https://example.cypress.io')

    cy.contains('type').click()
    
    cy.url().should('include', '/commands/actions')

    cy.get('.action-email')
      .type('fake@email.com')
      .should('have.value', 'fake@email.com')
  })
})

error monitoring

Summary

  • Looking for clues
    • console errors
  • Collecting witness statements
    • cross checking browser and system
  • Narrowing down suspect list
    • Techniques using Devtools and Git
  • Capturing
    • tests, error handling and monitoring

Questions ?

Thank you

@MariamReba

https://dev.to/ms_74

jsworld2022

By Mariam Reba Alexander

jsworld2022

  • 144