<!doctype html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="initial-scale=1.0"> <title>Assignment 7 - Tests for Tasks 1 and 2</title> <link rel="stylesheet" href="qunit/qunit-2.9.2.css"> </head> <body> <script src="js/fetch.js"></script> <script src="qunit/qunit-2.9.2.js"></script> <div id="qunit"></div> <div id="qunit-fixture"></div> <script> //some test payloads const headers = {}; const baseURL = "/test/fetch"; const jsonURL = baseURL + "/json/ok"; const body = "test body as a string" const jsonBody_req = { json: body, rnd: Math.random() }; const jsonBody_resp = (text) => { return { text, body: jsonBody_req } } var notValidJSON = () => {}; /* * Make sure the fetch_test/router.js is installed under /test/fetch and the server is running for these tests to work * */ function testOk(f,method,url,headers,body) { let msg = f.name+"('"+method+"','"+url+"','"+JSON.stringify(headers)+","+JSON.stringify(body)+") should accept the input"; return async function(assert) { try { await f(method,url,headers,body); result = true; } catch (error) { console.log(msg, error); msg += "\n but \n" + error; result = false; } assert.ok(result, msg); } } function testFail(f,method,url,headers,body) { return async function(assert) { try{ await f(method,url,headers,body); result = false; } catch(error) { result = true; } assert.ok(result, f.name+"("+JSON.stringify(method)+","+JSON.stringify(url)+","+JSON.stringify(headers)+","+JSON.stringify(body)+") should reject the input"); } } function testStatusBodyHeaders(f,method,url,headers,body,status,text,resp_headers) { return async function(assert) { return f(method,url,headers,body) .then((res)=>{ assert.equal(res.status, status, method+" "+url+" should return "+status+" status code"); Object.keys(resp_headers).forEach((k)=>{ assert.ok(res.headers.has(k), method+" "+url+" response includes header "+k); assert.equal(res.headers.get(k), resp_headers[k], method+" "+url+" response header "+k+" has expected value "+JSON.stringify(resp_headers[k])); }); return res.text(); }).then((resp)=>{ assert.equal(resp, text, method+" "+url+" returns expected response body "+JSON.stringify(text)); }); } } function testStatusBody(f,method,url,headers,body,status,text) { return async function(assert) { return f(method,url,headers,body) .then((res)=>{ assert.equal(res.status, status, method+" "+url+" should return "+status+" status code"); return res.text(); }).then((resp)=>{ assert.equal(resp, text, method+" "+url+" returns expected response body "+JSON.stringify(text)); }); } } function testStatusJSONBody(f,method,url,headers,body,status,json) { return async function(assert) { return f(method,url,headers,body) .then((res)=>{ //assert.equal(res.status, status, method+" "+url+" should return "+status+" status code"); assert.deepEqual(res, json, method+" "+url+" returns expected response body "+JSON.stringify(json)); }); } } function testStatus(f,method,url,headers,body,status,text) { return async function(assert) { return f(method,url,headers,body) .then((res)=>{ assert.equal(res.status, status, method+" "+url+" should return "+status+" status code"); }); } } function testRedirect(f,method,url,headers,body,text) { return async function(assert) { return f(method,url,headers,body) .then((res)=>{ assert.ok(res.redirected, method+" "+url+" should have been redirected"); return res.text(); }).then((resp)=>{ assert.equal(resp, text, method+" "+url+" has expected response body after redirection "+JSON.stringify(text)); }); } } function testAll(a){ return function(assert) { let b = []; a.forEach((f)=>{b.push(f(assert))}); return Promise.all(b); } } QUnit.module("Task 1: doFetchRequest Request Validation", {}); QUnit.test("reject incorrect methods", testAll( [ testFail(doFetchRequest,"WRONG", baseURL,headers), testFail(doFetchRequest,"RANDOM", baseURL,headers), testFail(doFetchRequest,"",baseURL,headers), testFail(doFetchRequest,undefined,baseURL,headers), testFail(doFetchRequest,404,baseURL,headers) ])); QUnit.test("GET, HEAD, OPTIONS, DELETE should not have a body", testAll( [ testFail(doFetchRequest,"GET", baseURL,headers,body), testFail(doFetchRequest,"HEAD", baseURL,headers,body), testFail(doFetchRequest,"OPTIONS",baseURL,headers,body), testFail(doFetchRequest,"DELETE",baseURL,headers,body), testOk(doFetchRequest,"GET", baseURL,headers), testOk(doFetchRequest,"HEAD", baseURL,headers), testOk(doFetchRequest,"OPTIONS",baseURL,headers), testOk(doFetchRequest,"DELETE",baseURL,headers) ])); QUnit.test("POST, PUT, PATCH require the body", testAll( [ testFail(doFetchRequest,"POST", baseURL,headers), testFail(doFetchRequest,"PUT", baseURL,headers), testFail(doFetchRequest,"PATCH",baseURL,headers), testOk(doFetchRequest,"POST", baseURL,headers,body), testOk(doFetchRequest,"PUT", baseURL,headers,body), testOk(doFetchRequest,"PATCH",baseURL,headers,body) ])); QUnit.test("POST, PUT, PATCH require a String body", testAll( [ testFail(doFetchRequest,"POST", baseURL,headers,{}), testFail(doFetchRequest,"PUT", baseURL,headers,{}), testFail(doFetchRequest,"PATCH",baseURL,headers,{}), testFail(doFetchRequest,"POST", baseURL,headers,[]), testFail(doFetchRequest,"PUT", baseURL,headers,[]), testFail(doFetchRequest,"PATCH",baseURL,headers,[]), testFail(doFetchRequest,"POST", baseURL,headers,999), testFail(doFetchRequest,"PUT", baseURL,headers,999), testFail(doFetchRequest,"PATCH",baseURL,headers,999) ])); QUnit.module("Task 1: doFetchRequest Response Validation", {}); QUnit.test("GET/DELETE return expected status and body", testAll( [ testStatusBody(doFetchRequest,"GET",baseURL,{"Accept": 'text/html'},undefined,200,"GET Working"), testStatus(doFetchRequest,"GET",baseURL+"/not/found",{"Accept": 'text/html'},undefined,404), testStatusBody(doFetchRequest,"GET",baseURL,{"Accept": 'application/json'},undefined,200,"{\"text\":\"GET Working\"}"), testStatusBody(doFetchRequest,"DELETE",baseURL,{"Accept": 'text/html'},undefined,204,"") ])); QUnit.test("GET follows redirects", testAll( [ testRedirect(doFetchRequest,"GET",baseURL+"/redirect",{"Accept": 'text/html'},undefined,"Redirect Works") ])); QUnit.test("POST returns expected status, body and headers", testAll( [ testStatusBodyHeaders(doFetchRequest,"POST",baseURL+"/new",{"Accept": 'text/html'},"X",201,"POST Working\nX",{'Location':'42'}), testStatusBodyHeaders(doFetchRequest,"POST",baseURL+"/new",{"Accept": 'application/json'},"JSON",201,"{\"text\":\"POST Working\",\"body\":\"JSON\"}",{'Location':'24', 'Content-Type': 'application/json; charset=utf-8'}) ])); QUnit.test("PUT returns expected status, body and headers", testAll( [ testStatusBody(doFetchRequest,"PUT",baseURL+"/echo",{"Accept": 'text/html'},"X",200,"X"), testStatusBodyHeaders(doFetchRequest,"PUT",baseURL+"/echo",{"Accept": 'application/json'},"JSON",200,"{\"text\":\"PUT Working\",\"body\":\"JSON\"}",{'Content-Type': 'application/json; charset=utf-8'}) ])); QUnit.module("Task 2: doJSONRequest Request Validation", {}); QUnit.test("reject incorrect methods", testAll( [ testFail(doJSONRequest,"WRONG", jsonURL,headers), testFail(doJSONRequest,"RANDOM", jsonURL,headers), testFail(doJSONRequest,"", jsonURL,headers), testFail(doJSONRequest,undefined, jsonURL,headers), testFail(doJSONRequest,404, jsonURL,headers) ])); QUnit.test("GET, HEAD, OPTIONS, DELETE should not have a body", testAll( [ testFail(doJSONRequest,"GET", jsonURL,headers,body), testFail(doJSONRequest,"HEAD", jsonURL,headers,body), testFail(doJSONRequest,"OPTIONS",jsonURL,headers,body), testFail(doJSONRequest,"DELETE", jsonURL,headers,body), testOk(doJSONRequest,"GET", jsonURL,headers), //HEAD will also have an empty response body //testOk(doJSONRequest,"HEAD", jsonURL,headers), testOk(doJSONRequest,"OPTIONS",jsonURL,headers), testOk(doJSONRequest,"DELETE", jsonURL,headers) ])); QUnit.test("POST, PUT, PATCH should not have a String body", testAll( [ testFail(doJSONRequest,"POST", jsonURL,headers,body), testFail(doJSONRequest,"PUT", jsonURL,headers,body), testFail(doJSONRequest,"PATCH",jsonURL,headers,body), testFail(doJSONRequest,"POST", jsonURL,headers,999), testFail(doJSONRequest,"PUT", jsonURL,headers,999), testFail(doJSONRequest,"PATCH",jsonURL,headers,999), testFail(doJSONRequest,"POST", jsonURL,headers,notValidJSON), testFail(doJSONRequest,"PUT", jsonURL,headers,notValidJSON), testFail(doJSONRequest,"PATCH",jsonURL,headers,notValidJSON) ])); QUnit.test("POST, PUT, PATCH require an Object/Array body", testAll( [ testOk(doJSONRequest,"POST", jsonURL,headers,{}), testOk(doJSONRequest,"PUT", jsonURL,headers,{}), testOk(doJSONRequest,"PATCH",jsonURL,headers,{}), testOk(doJSONRequest,"POST", jsonURL,headers,[]), testOk(doJSONRequest,"PUT", jsonURL,headers,[]), testOk(doJSONRequest,"PATCH",jsonURL,headers,[]) ])); QUnit.test("ignore correct accept/content-type headers", testAll( [ testOk(doJSONRequest,"POST", jsonURL,{'Accept': 'application/json'},{}), testOk(doJSONRequest,"PUT", jsonURL,{'Accept': 'application/json'},{}), testOk(doJSONRequest,"PATCH",jsonURL,{'Accept': 'application/json'},{}), testOk(doJSONRequest,"POST", jsonURL,{'Accept': 'application/json', 'Content-Type': 'application/json'},{}), testOk(doJSONRequest,"PUT", jsonURL,{'Accept': 'application/json', 'Content-Type': 'application/json'},{}), testOk(doJSONRequest,"PATCH", jsonURL,{'Accept': 'application/json', 'Content-Type': 'application/json'},{}), testOk(doJSONRequest,"PUT", jsonURL,{'Accept': 'application/json'},{}), testOk(doJSONRequest,"PATCH",jsonURL,{'Accept': 'application/json'},{}), testOk(doJSONRequest,"GET", jsonURL,{'Accept': 'application/json'}), testOk(doJSONRequest,"OPTIONS", jsonURL,{'Accept': 'application/json'}), testOk(doJSONRequest,"DELETE",jsonURL,{'Accept': 'application/json'}) ])); QUnit.test("reject incorrect accept/content-type headers", testAll( [ testFail(doJSONRequest,"POST", jsonURL,{'Accept': 'text/plain'},{}), testFail(doJSONRequest,"PUT", jsonURL,{'Accept': 'text/plain'},{}), testFail(doJSONRequest,"PATCH",jsonURL,{'Accept': 'text/plain'},{}), testFail(doJSONRequest,"POST", jsonURL,{'Accept': 'text/plain', 'Content-Type': 'text/plain'},{}), testFail(doJSONRequest,"PUT", jsonURL,{'Accept': 'text/plain', 'Content-Type': 'text/plain'},{}), testFail(doJSONRequest,"PATCH", jsonURL,{'Accept': 'text/plain', 'Content-Type': 'text/plain'},{}), testFail(doJSONRequest,"PUT", jsonURL,{'Accept': 'text/plain'},{}), testFail(doJSONRequest,"PATCH",jsonURL,{'Accept': 'text/plain'},{}), testFail(doJSONRequest,"GET", jsonURL,{'Accept': 'text/plain'}), testFail(doJSONRequest,"OPTIONS", jsonURL,{'Accept': 'text/plain'}), testFail(doJSONRequest,"DELETE",jsonURL,{'Accept': 'text/plain'}) ])); QUnit.module("Task 2: doJSONRequest Response Validation", {}); QUnit.test("returns expected JSON body", testAll( [ testStatusJSONBody(doJSONRequest,"PUT",baseURL+"/echo",headers,jsonBody_req,200,jsonBody_resp("PUT Working")), testStatusJSONBody(doJSONRequest,"POST",baseURL+"/new",headers,jsonBody_req,201,jsonBody_resp("POST Working")), testStatusJSONBody(doJSONRequest,"DELETE",baseURL,headers,undefined,204,{status: 204, text: 'DELETE Working'}), testStatusJSONBody(doJSONRequest,"GET",jsonURL,headers,undefined,200,{text: 'ok'}), testStatusJSONBody(doJSONRequest,"PATCH",jsonURL,headers,{},200,{text: 'ok'}), testStatusJSONBody(doJSONRequest,"GET",baseURL,headers,undefined,200,{text: 'GET Working'}) ])); </script> </body> </html>