Debug

like a detective

Mariam reba Alexander

Software Engineer

web

security

 Maersk.com - Logistics HUB

LivES in Denmark

KERALA, SOUTH INDIA

MYSTERIES

INVESTIGATE

  1. Look for clues
  2. Collect witness statements
  3. Narrow down suspect list
  4. Capture the culprit

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

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

2. collect witness statements

Cross-checking

  • Compare cross-browser
  • Compare with another system
  • Git compare

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

Debugging techniques 

  • Brute force method
  • Back tracking 
  • Cause Elimination Method

devtools

Code

    <p>Click the button below to get suggestions on what you can do</p>
    <button class="button-1" @click="getSuggestion">
      Suggest me
    </button>
      <h3>{{ response.data.activity }}</h3>
      <p>{{ response.data.type }}</p>
  </div>
</template>

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

$0- $4 (console utilities API)

Break points

conditional Break points

watch

Live expressions

FIX

    <p>Click the button below to get suggestions on what you can do</p>
    <button class="button-1" @click="getSuggestion">
      Suggest me
    </button>
    <template v-if="response.data">
      <h3>{{ response.data.activity }}</h3>
      <p>{{ response.data.type }}</p>
    </template>
  </div>
</template>

<script>
import axios from "axios";
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data() {
    return {
      response: {}
    }
  },
  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

deck

By Mariam Reba Alexander

Private