{
  "info": {
    "name": "Todo Personal · authentication and isolation",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "item": [
    {
      "name": "01 Register Alice",
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const run=Date.now().toString() + Math.random().toString(36).slice(2,8);",
              "pm.environment.set('aliceEmail','alice.'+run+'@example.com');",
              "pm.environment.set('bobEmail','bob.'+run+'@example.com');",
              "pm.environment.unset('aliceToken');",
              "pm.environment.unset('bobToken');",
              "pm.environment.unset('aliceTodoId');"
            ]
          }
        },
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('HTTP 201', () => pm.response.to.have.status(201));"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{baseAuthUrl}}/api/auth/register",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"email\": \"{{aliceEmail}}\",\n  \"password\": \"AlicePass123!\"\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      }
    },
    {
      "name": "02 Duplicate Alice",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('HTTP 409', () => pm.response.to.have.status(409));"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{baseAuthUrl}}/api/auth/register",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"email\": \"{{aliceEmail}}\",\n  \"password\": \"AlicePass123!\"\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      }
    },
    {
      "name": "03 Login Alice",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('HTTP 200', () => pm.response.to.have.status(200));",
              "if(pm.response.code === 200) pm.environment.set('aliceToken',pm.response.json().accessToken);"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{baseAuthUrl}}/api/auth/login",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"email\": \"{{aliceEmail}}\",\n  \"password\": \"AlicePass123!\"\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      }
    },
    {
      "name": "04 Alice creates",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('HTTP 201', () => pm.response.to.have.status(201));",
              "if(pm.response.code === 201) pm.environment.set('aliceTodoId',pm.response.json().id);"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{baseAuthUrl}}/api/todos",
        "auth": {
          "type": "bearer",
          "bearer": [
            {
              "key": "token",
              "value": "{{aliceToken}}",
              "type": "string"
            }
          ]
        },
        "body": {
          "mode": "raw",
          "raw": "{\n  \"title\": \"Alice private task\",\n  \"completed\": false\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      }
    },
    {
      "name": "05 Register Bob",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('HTTP 201', () => pm.response.to.have.status(201));"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{baseAuthUrl}}/api/auth/register",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"email\": \"{{bobEmail}}\",\n  \"password\": \"BobPass123!\"\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      }
    },
    {
      "name": "06 Login Bob",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('HTTP 200', () => pm.response.to.have.status(200));",
              "if(pm.response.code === 200) pm.environment.set('bobToken',pm.response.json().accessToken);"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{baseAuthUrl}}/api/auth/login",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"email\": \"{{bobEmail}}\",\n  \"password\": \"BobPass123!\"\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      }
    },
    {
      "name": "07 Bob list excludes Alice",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('HTTP 200', () => pm.response.to.have.status(200));",
              "pm.test('No Alice task', () => pm.expect(pm.response.json().some(t => t.id === pm.environment.get('aliceTodoId'))).to.eql(false));"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [],
        "url": "{{baseAuthUrl}}/api/todos",
        "auth": {
          "type": "bearer",
          "bearer": [
            {
              "key": "token",
              "value": "{{bobToken}}",
              "type": "string"
            }
          ]
        }
      }
    },
    {
      "name": "08 Bob cannot read Alice",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('HTTP 404', () => pm.response.to.have.status(404));"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [],
        "url": "{{baseAuthUrl}}/api/todos/{{aliceTodoId}}",
        "auth": {
          "type": "bearer",
          "bearer": [
            {
              "key": "token",
              "value": "{{bobToken}}",
              "type": "string"
            }
          ]
        }
      }
    },
    {
      "name": "09 Bob cannot update Alice",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('HTTP 404', () => pm.response.to.have.status(404));"
            ]
          }
        }
      ],
      "request": {
        "method": "PUT",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{baseAuthUrl}}/api/todos/{{aliceTodoId}}",
        "auth": {
          "type": "bearer",
          "bearer": [
            {
              "key": "token",
              "value": "{{bobToken}}",
              "type": "string"
            }
          ]
        },
        "body": {
          "mode": "raw",
          "raw": "{\n  \"title\": \"Hacked\",\n  \"completed\": true\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      }
    },
    {
      "name": "10 Bob cannot delete Alice",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('HTTP 404', () => pm.response.to.have.status(404));"
            ]
          }
        }
      ],
      "request": {
        "method": "DELETE",
        "header": [],
        "url": "{{baseAuthUrl}}/api/todos/{{aliceTodoId}}",
        "auth": {
          "type": "bearer",
          "bearer": [
            {
              "key": "token",
              "value": "{{bobToken}}",
              "type": "string"
            }
          ]
        }
      }
    },
    {
      "name": "11 Alice unchanged",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('HTTP 200', () => pm.response.to.have.status(200));",
              "pm.test('Unchanged', () => {pm.expect(pm.response.json().title).to.eql('Alice private task'); pm.expect(pm.response.json().completed).to.eql(false);});"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [],
        "url": "{{baseAuthUrl}}/api/todos/{{aliceTodoId}}",
        "auth": {
          "type": "bearer",
          "bearer": [
            {
              "key": "token",
              "value": "{{aliceToken}}",
              "type": "string"
            }
          ]
        }
      }
    },
    {
      "name": "12 Alice updates",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('HTTP 200', () => pm.response.to.have.status(200));",
              "pm.test('Completed', () => pm.expect(pm.response.json().completed).to.eql(true));"
            ]
          }
        }
      ],
      "request": {
        "method": "PUT",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{baseAuthUrl}}/api/todos/{{aliceTodoId}}",
        "auth": {
          "type": "bearer",
          "bearer": [
            {
              "key": "token",
              "value": "{{aliceToken}}",
              "type": "string"
            }
          ]
        },
        "body": {
          "mode": "raw",
          "raw": "{\n  \"title\": \"Alice completed task\",\n  \"completed\": true\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      }
    },
    {
      "name": "13 No token rejected",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('HTTP 401', () => pm.response.to.have.status(401));"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [],
        "url": "{{baseAuthUrl}}/api/todos"
      }
    },
    {
      "name": "14 Invalid token rejected",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('HTTP 401', () => pm.response.to.have.status(401));"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [],
        "url": "{{baseAuthUrl}}/api/todos",
        "auth": {
          "type": "bearer",
          "bearer": [
            {
              "key": "token",
              "value": "invalid-token",
              "type": "string"
            }
          ]
        }
      }
    },
    {
      "name": "15 Wrong password rejected",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('HTTP 401', () => pm.response.to.have.status(401));"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{baseAuthUrl}}/api/auth/login",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"email\": \"{{aliceEmail}}\",\n  \"password\": \"WrongPass123!\"\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      }
    },
    {
      "name": "16 Blank title rejected",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('HTTP 400', () => pm.response.to.have.status(400));"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{baseAuthUrl}}/api/todos",
        "auth": {
          "type": "bearer",
          "bearer": [
            {
              "key": "token",
              "value": "{{aliceToken}}",
              "type": "string"
            }
          ]
        },
        "body": {
          "mode": "raw",
          "raw": "{\n  \"title\": \" \",\n  \"completed\": false\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      }
    },
    {
      "name": "17 Alice deletes",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('HTTP 204', () => pm.response.to.have.status(204));"
            ]
          }
        }
      ],
      "request": {
        "method": "DELETE",
        "header": [],
        "url": "{{baseAuthUrl}}/api/todos/{{aliceTodoId}}",
        "auth": {
          "type": "bearer",
          "bearer": [
            {
              "key": "token",
              "value": "{{aliceToken}}",
              "type": "string"
            }
          ]
        }
      }
    },
    {
      "name": "18 Alice task gone",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('HTTP 404', () => pm.response.to.have.status(404));"
            ]
          }
        }
      ],
      "request": {
        "method": "GET",
        "header": [],
        "url": "{{baseAuthUrl}}/api/todos/{{aliceTodoId}}",
        "auth": {
          "type": "bearer",
          "bearer": [
            {
              "key": "token",
              "value": "{{aliceToken}}",
              "type": "string"
            }
          ]
        }
      }
    }
  ]
}