diff --git a/servant-js/examples/counter.hs b/servant-js/examples/counter.hs index 86f274dd..5462b6f2 100644 --- a/servant-js/examples/counter.hs +++ b/servant-js/examples/counter.hs @@ -92,6 +92,8 @@ main = do writeJSForAPI testApi (angular defAngularOptions) (www "angular" "api.js") + writeJSForAPI testApi axios (www "axios" "api.js") + writeServiceJS (www "angular" "api.service.js") -- setup a shared counter diff --git a/servant-js/examples/www/axios/axios.min.js b/servant-js/examples/www/axios/axios.min.js new file mode 100644 index 00000000..3e3e2da5 --- /dev/null +++ b/servant-js/examples/www/axios/axios.min.js @@ -0,0 +1,10 @@ +/* axios v0.5.4 | (c) 2015 by Matt Zabriskie */ +var axios=function(t){function e(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return t[r].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var n={};return e.m=t,e.c=n,e.p="",e(0)}([function(t,e,n){t.exports=n(1)},function(t,e,n){"use strict";var r=n(2),o=n(3),i=n(4),s=n(5),u=n(6);!function(){var t=n(9);t&&"function"==typeof t.polyfill&&t.polyfill()}();var a=t.exports=function c(t){t=o.merge({method:"get",headers:{},transformRequest:r.transformRequest,transformResponse:r.transformResponse},t),t.withCredentials=t.withCredentials||r.withCredentials;var e=[s,void 0],n=Promise.resolve(t);for(c.interceptors.request.forEach(function(t){e.unshift(t.fulfilled,t.rejected)}),c.interceptors.response.forEach(function(t){e.push(t.fulfilled,t.rejected)});e.length;)n=n.then(e.shift(),e.shift());return n.success=function(t){return i("success","then","https://github.com/mzabriskie/axios/blob/master/README.md#response-api"),n.then(function(e){t(e.data,e.status,e.headers,e.config)}),n},n.error=function(t){return i("error","catch","https://github.com/mzabriskie/axios/blob/master/README.md#response-api"),n.then(null,function(e){t(e.data,e.status,e.headers,e.config)}),n},n};a.defaults=r,a.all=function(t){return Promise.all(t)},a.spread=n(7),a.interceptors={request:new u,response:new u},function(){function t(){o.forEach(arguments,function(t){a[t]=function(e,n){return a(o.merge(n||{},{method:t,url:e}))}})}function e(){o.forEach(arguments,function(t){a[t]=function(e,n,r){return a(o.merge(r||{},{method:t,url:e,data:n}))}})}t("delete","get","head"),e("post","put","patch")}()},function(t,e,n){"use strict";var r=n(3),o=/^\)\]\}',?\n/,i={"Content-Type":"application/x-www-form-urlencoded"};t.exports={transformRequest:[function(t,e){return r.isFormData(t)?t:r.isArrayBuffer(t)?t:r.isArrayBufferView(t)?t.buffer:!r.isObject(t)||r.isFile(t)||r.isBlob(t)?t:(!r.isUndefined(e)&&r.isUndefined(e["Content-Type"])&&(e["Content-Type"]="application/json;charset=utf-8"),JSON.stringify(t))}],transformResponse:[function(t){if("string"==typeof t){t=t.replace(o,"");try{t=JSON.parse(t)}catch(e){}}return t}],headers:{common:{Accept:"application/json, text/plain, */*"},patch:r.merge(i),post:r.merge(i),put:r.merge(i)},xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN"}},function(t){"use strict";function e(t){return"[object Array]"===m.call(t)}function n(t){return"[object ArrayBuffer]"===m.call(t)}function r(t){return"[object FormData]"===m.call(t)}function o(t){return"undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(t):t&&t.buffer&&t.buffer instanceof ArrayBuffer}function i(t){return"string"==typeof t}function s(t){return"number"==typeof t}function u(t){return"undefined"==typeof t}function a(t){return null!==t&&"object"==typeof t}function c(t){return"[object Date]"===m.call(t)}function f(t){return"[object File]"===m.call(t)}function l(t){return"[object Blob]"===m.call(t)}function p(t){return t.replace(/^\s*/,"").replace(/\s*$/,"")}function h(t,n){if(null!==t&&"undefined"!=typeof t){var r=e(t)||"object"==typeof t&&!isNaN(t.length);if("object"==typeof t||r||(t=[t]),r)for(var o=0,i=t.length;i>o;o++)n.call(null,t[o],o,t);else for(var s in t)t.hasOwnProperty(s)&&n.call(null,t[s],s,t)}}function d(){var t={};return h(arguments,function(e){h(e,function(e,n){t[n]=e})}),t}var m=Object.prototype.toString;t.exports={isArray:e,isArrayBuffer:n,isFormData:r,isArrayBufferView:o,isString:i,isNumber:s,isObject:a,isUndefined:u,isDate:c,isFile:f,isBlob:l,forEach:h,merge:d,trim:p}},function(t){"use strict";t.exports=function(t,e,n){try{console.warn("DEPRECATED method `"+t+"`."+(e?" Use `"+e+"` instead.":"")+" This method will be removed in a future release."),n&&console.warn("For more information about usage see "+n)}catch(r){}}},function(t,e,n){(function(e){"use strict";t.exports=function(t){return new Promise(function(r,o){try{"undefined"!=typeof window?n(8)(r,o,t):"undefined"!=typeof e&&n(8)(r,o,t)}catch(i){o(i)}})}}).call(e,n(10))},function(t,e,n){"use strict";function r(){this.handlers=[]}var o=n(3);r.prototype.use=function(t,e){return this.handlers.push({fulfilled:t,rejected:e}),this.handlers.length-1},r.prototype.eject=function(t){this.handlers[t]&&(this.handlers[t]=null)},r.prototype.forEach=function(t){o.forEach(this.handlers,function(e){null!==e&&t(e)})},t.exports=r},function(t){"use strict";t.exports=function(t){return function(e){t.apply(null,e)}}},function(t,e,n){"use strict";var r=n(2),o=n(3),i=n(11),s=n(12),u=n(13),a=n(14),c=n(15);t.exports=function(t,e,n){var f=a(n.data,n.headers,n.transformRequest),l=o.merge(r.headers.common,r.headers[n.method]||{},n.headers||{});o.isFormData(f)&&delete l["Content-Type"];var p=new(XMLHttpRequest||ActiveXObject)("Microsoft.XMLHTTP");p.open(n.method.toUpperCase(),i(n.url,n.params),!0),p.onreadystatechange=function(){if(p&&4===p.readyState){var r=u(p.getAllResponseHeaders()),o=-1!==["text",""].indexOf(n.responseType||"")?p.responseText:p.response,i={data:a(o,r,n.transformResponse),status:p.status,statusText:p.statusText,headers:r,config:n};(p.status>=200&&p.status<300?t:e)(i),p=null}};var h=c(n.url)?s.read(n.xsrfCookieName||r.xsrfCookieName):void 0;if(h&&(l[n.xsrfHeaderName||r.xsrfHeaderName]=h),o.forEach(l,function(t,e){f||"content-type"!==e.toLowerCase()?p.setRequestHeader(e,t):delete l[e]}),n.withCredentials&&(p.withCredentials=!0),n.responseType)try{p.responseType=n.responseType}catch(d){if("json"!==p.responseType)throw d}o.isArrayBuffer(f)&&(f=new DataView(f)),p.send(f)}},function(t,e,n){var r;(function(t,o,i){/*! + * @overview es6-promise - a tiny implementation of Promises/A+. + * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald) + * @license Licensed under MIT license + * See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE + * @version 2.0.1 + */ +(function(){"use strict";function s(t){return"function"==typeof t||"object"==typeof t&&null!==t}function u(t){return"function"==typeof t}function a(t){return"object"==typeof t&&null!==t}function c(){}function f(){return function(){t.nextTick(d)}}function l(){var t=0,e=new X(d),n=document.createTextNode("");return e.observe(n,{characterData:!0}),function(){n.data=t=++t%2}}function p(){var t=new MessageChannel;return t.port1.onmessage=d,function(){t.port2.postMessage(0)}}function h(){return function(){setTimeout(d,1)}}function d(){for(var t=0;H>t;t+=2){var e=J[t],n=J[t+1];e(n),J[t]=void 0,J[t+1]=void 0}H=0}function m(){}function y(){return new TypeError("You cannot resolve a promise with itself")}function v(){return new TypeError("A promises callback cannot return that same promise.")}function w(t){try{return t.then}catch(e){return z.error=e,z}}function g(t,e,n,r){try{t.call(e,n,r)}catch(o){return o}}function b(t,e,n){L(function(t){var r=!1,o=g(n,e,function(n){r||(r=!0,e!==n?A(t,n):j(t,n))},function(e){r||(r=!0,T(t,e))},"Settle: "+(t._label||" unknown promise"));!r&&o&&(r=!0,T(t,o))},t)}function _(t,e){e._state===Y?j(t,e._result):t._state===$?T(t,e._result):C(e,void 0,function(e){A(t,e)},function(e){T(t,e)})}function x(t,e){if(e.constructor===t.constructor)_(t,e);else{var n=w(e);n===z?T(t,z.error):void 0===n?j(t,e):u(n)?b(t,e,n):j(t,e)}}function A(t,e){t===e?T(t,y()):s(e)?x(t,e):j(t,e)}function E(t){t._onerror&&t._onerror(t._result),R(t)}function j(t,e){t._state===K&&(t._result=e,t._state=Y,0===t._subscribers.length||L(R,t))}function T(t,e){t._state===K&&(t._state=$,t._result=e,L(E,t))}function C(t,e,n,r){var o=t._subscribers,i=o.length;t._onerror=null,o[i]=e,o[i+Y]=n,o[i+$]=r,0===i&&t._state&&L(R,t)}function R(t){var e=t._subscribers,n=t._state;if(0!==e.length){for(var r,o,i=t._result,s=0;s1)throw new Error("Second argument not supported");if("object"!=typeof t)throw new TypeError("Argument must be an object");return c.prototype=t,new c},0),L=function(t,e){J[H]=t,J[H+1]=e,H+=2,2===H&&U()},I="undefined"!=typeof window?window:{},X=I.MutationObserver||I.WebKitMutationObserver,V="undefined"!=typeof Uint8ClampedArray&&"undefined"!=typeof importScripts&&"undefined"!=typeof MessageChannel,J=new Array(1e3);U="undefined"!=typeof t&&"[object process]"==={}.toString.call(t)?f():X?l():V?p():h();var K=void 0,Y=1,$=2,z=new S,G=new S;D.prototype._validateInput=function(t){return q(t)},D.prototype._validationError=function(){return new Error("Array Methods must be provided an Array")},D.prototype._init=function(){this._result=new Array(this.length)};var W=D;D.prototype._enumerate=function(){for(var t=this.length,e=this.promise,n=this._input,r=0;e._state===K&&t>r;r++)this._eachEntry(n[r],r)},D.prototype._eachEntry=function(t,e){var n=this._instanceConstructor;a(t)?t.constructor===n&&t._state!==K?(t._onerror=null,this._settledAt(t._state,e,t._result)):this._willSettleAt(n.resolve(t),e):(this._remaining--,this._result[e]=this._makeResult(Y,e,t))},D.prototype._settledAt=function(t,e,n){var r=this.promise;r._state===K&&(this._remaining--,this._abortOnReject&&t===$?T(r,n):this._result[e]=this._makeResult(t,e,n)),0===this._remaining&&j(r,this._result)},D.prototype._makeResult=function(t,e,n){return n},D.prototype._willSettleAt=function(t,e){var n=this;C(t,void 0,function(t){n._settledAt(Y,e,t)},function(t){n._settledAt($,e,t)})};var Q=function(t,e){return new W(this,t,!0,e).promise},Z=function(t,e){function n(t){A(i,t)}function r(t){T(i,t)}var o=this,i=new o(m,e);if(!q(t))return T(i,new TypeError("You must pass an array to race.")),i;for(var s=t.length,u=0;i._state===K&&s>u;u++)C(o.resolve(t[u]),void 0,n,r);return i},te=function(t,e){var n=this;if(t&&"object"==typeof t&&t.constructor===n)return t;var r=new n(m,e);return A(r,t),r},ee=function(t,e){var n=this,r=new n(m,e);return T(r,t),r},ne=0,re=M;M.all=Q,M.race=Z,M.resolve=te,M.reject=ee,M.prototype={constructor:M,then:function(t,e){var n=this,r=n._state;if(r===Y&&!t||r===$&&!e)return this;var o=new this.constructor(m),i=n._result;if(r){var s=arguments[r-1];L(function(){P(r,o,s,i)})}else C(n,o,t,e);return o},"catch":function(t){return this.then(null,t)}};var oe=function(){var t;t="undefined"!=typeof o?o:"undefined"!=typeof window&&window.document?window:self;var e="Promise"in t&&"resolve"in t.Promise&&"reject"in t.Promise&&"all"in t.Promise&&"race"in t.Promise&&function(){var e;return new t.Promise(function(t){e=t}),u(e)}();e||(t.Promise=re)},ie={Promise:re,polyfill:oe};n(16).amd?(r=function(){return ie}.call(e,n,e,i),!(void 0!==r&&(i.exports=r))):"undefined"!=typeof i&&i.exports?i.exports=ie:"undefined"!=typeof this&&(this.ES6Promise=ie)}).call(this)}).call(e,n(10),function(){return this}(),n(17)(t))},function(t){function e(){if(!i){i=!0;for(var t,e=o.length;e;){t=o,o=[];for(var n=-1;++n0&&(t+=(-1===t.indexOf("?")?"?":"&")+n.join("&")),t}},function(t,e,n){"use strict";var r=n(3);t.exports={write:function(t,e,n,o,i,s){var u=[];u.push(t+"="+encodeURIComponent(e)),r.isNumber(n)&&u.push("expires="+new Date(n).toGMTString()),r.isString(o)&&u.push("path="+o),r.isString(i)&&u.push("domain="+i),s===!0&&u.push("secure"),document.cookie=u.join("; ")},read:function(t){var e=document.cookie.match(new RegExp("(^|;\\s*)("+t+")=([^;]*)"));return e?decodeURIComponent(e[3]):null},remove:function(t){this.write(t,"",Date.now()-864e5)}}},function(t,e,n){"use strict";var r=n(3);t.exports=function(t){var e,n,o,i={};return t?(r.forEach(t.split("\n"),function(t){o=t.indexOf(":"),e=r.trim(t.substr(0,o)).toLowerCase(),n=r.trim(t.substr(o+1)),e&&(i[e]=i[e]?i[e]+", "+n:n)}),i):i}},function(t,e,n){"use strict";var r=n(3);t.exports=function(t,e,n){return r.forEach(n,function(n){t=n(t,e)}),t}},function(t,e,n){"use strict";function r(t){var e=t;return s&&(u.setAttribute("href",e),e=u.href),u.setAttribute("href",e),{href:u.href,protocol:u.protocol?u.protocol.replace(/:$/,""):"",host:u.host,search:u.search?u.search.replace(/^\?/,""):"",hash:u.hash?u.hash.replace(/^#/,""):"",hostname:u.hostname,port:u.port,pathname:"/"===u.pathname.charAt(0)?u.pathname:"/"+u.pathname}}var o,i=n(3),s=/(msie|trident)/i.test(navigator.userAgent),u=document.createElement("a");o=r(window.location.href),t.exports=function(t){var e=i.isString(t)?r(t):t;return e.protocol===o.protocol&&e.host===o.host}},function(t){t.exports=function(){throw new Error("define cannot be used indirect")}},function(t){t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children=[],t.webpackPolyfill=1),t}}]); +//# sourceMappingURL=axios.min.map \ No newline at end of file diff --git a/servant-js/examples/www/axios/index.html b/servant-js/examples/www/axios/index.html new file mode 100644 index 00000000..2f3a0d7c --- /dev/null +++ b/servant-js/examples/www/axios/index.html @@ -0,0 +1,40 @@ + + + Servant: counter + + + +

Axios version

+Counter: 0 + + + + + + + diff --git a/servant-js/examples/www/index.html b/servant-js/examples/www/index.html index 4c55aea4..b9411ac1 100644 --- a/servant-js/examples/www/index.html +++ b/servant-js/examples/www/index.html @@ -5,13 +5,15 @@ body { text-align: center; } #counter { color: green; } #inc { margin: 0px 20px; background-color: green; color: white; } + iframe { height: 20%; width: 80%} - - - - + + + + + diff --git a/servant-js/servant-js.cabal b/servant-js/servant-js.cabal index 9668bf6a..239afbb9 100644 --- a/servant-js/servant-js.cabal +++ b/servant-js/servant-js.cabal @@ -36,6 +36,7 @@ flag example library exposed-modules: Servant.JS Servant.JS.Angular + Servant.JS.Axios Servant.JS.JQuery Servant.JS.Vanilla Servant.JS.Internal diff --git a/servant-js/src/Servant/JS.hs b/servant-js/src/Servant/JS.hs index 23835d21..6381bb6c 100644 --- a/servant-js/src/Servant/JS.hs +++ b/servant-js/src/Servant/JS.hs @@ -100,6 +100,12 @@ module Servant.JS , AngularOptions(..) , defAngularOptions + , -- * Axios code generation + axios + , axiosWith + , AxiosOptions(..) + , defAxiosOptions + , -- * Misc. listFromAPI , javascript @@ -111,6 +117,7 @@ module Servant.JS import Data.Proxy import Servant.API import Servant.JS.Angular +import Servant.JS.Axios import Servant.JS.Internal import Servant.JS.JQuery import Servant.JS.Vanilla diff --git a/servant-js/src/Servant/JS/Axios.hs b/servant-js/src/Servant/JS/Axios.hs new file mode 100644 index 00000000..bd62f80f --- /dev/null +++ b/servant-js/src/Servant/JS/Axios.hs @@ -0,0 +1,129 @@ +module Servant.JS.Axios where + +import Servant.JS.Internal +import Control.Lens +import Data.Char (toLower) +import Data.List +import Data.Monoid + +-- | Axios 'configuration' type +-- Let you customize the generation using Axios capabilities +data AxiosOptions = AxiosOptions + { -- | indicates whether or not cross-site Access-Control requests + -- should be made using credentials + withCredentials :: !Bool + -- | the name of the cookie to use as a value for xsrf token + , xsrfCookieName :: !(Maybe String) + -- | the name of the header to use as a value for xsrf token + , xsrfHeaderName :: !(Maybe String) + } + +-- | Default instance of the AxiosOptions +-- Defines the settings as they are in the Axios documentation +-- by default +defAxiosOptions :: AxiosOptions +defAxiosOptions = AxiosOptions + { withCredentials = False + , xsrfCookieName = Nothing + , xsrfHeaderName = Nothing + } + +-- | Generate regular javacript functions that use +-- the axios library, using default values for 'CommonGeneratorOptions'. +axios :: AxiosOptions -> JavaScriptGenerator +axios aopts = axiosWith aopts defCommonGeneratorOptions + +-- | Generate regular javascript functions that use the axios library. +axiosWith :: AxiosOptions -> CommonGeneratorOptions -> JavaScriptGenerator +axiosWith aopts opts = intercalate "\n\n" . map (generateAxiosJSWith aopts opts) + +-- | js codegen using axios library using default options +generateAxiosJS :: AxiosOptions -> AjaxReq -> String +generateAxiosJS aopts = generateAxiosJSWith aopts defCommonGeneratorOptions + +-- | js codegen using axios library +generateAxiosJSWith :: AxiosOptions -> CommonGeneratorOptions -> AjaxReq -> String +generateAxiosJSWith aopts opts req = "\n" <> + fname <> " = function(" <> argsStr <> ")\n" + <> "{\n" + <> " return axios({ url: " <> url <> "\n" + <> " , method: '" <> method <> "'\n" + <> dataBody + <> reqheaders + <> withCreds + <> xsrfCookie + <> xsrfHeader + <> " });\n" + <> "}\n" + + where argsStr = intercalate ", " args + args = captures + ++ map (view argName) queryparams + ++ body + ++ map (toValidFunctionName . (<>) "header" . headerArgName) hs + + captures = map captureArg + . filter isCapture + $ req ^. reqUrl.path + + hs = req ^. reqHeaders + + queryparams = req ^.. reqUrl.queryStr.traverse + + body = if req ^. reqBody + then [requestBody opts] + else [] + + dataBody = + if req ^. reqBody + then " , data: body\n" <> + " , responseType: 'json'\n" + else "" + + withCreds = + if withCredentials aopts + then " , withCredentials: true\n" + else "" + + xsrfCookie = + case xsrfCookieName aopts of + Just name -> " , xsrfCookieName: '" <> name <> "'\n" + Nothing -> "" + + xsrfHeader = + case xsrfHeaderName aopts of + Just name -> " , xsrfHeaderName: '" <> name <> "'\n" + Nothing -> "" + + reqheaders = + if null hs + then "" + else " , headers: { " <> headersStr <> " }\n" + + where headersStr = intercalate ", " $ map headerStr hs + headerStr header = "\"" ++ + headerArgName header ++ + "\": " ++ show header + + namespace = + if hasNoModule + then "var " + else (moduleName opts) <> "." + where + hasNoModule = null (moduleName opts) + + fname = namespace <> (functionNameBuilder opts $ req ^. funcName) + + method = map toLower $ req ^. reqMethod + url = if url' == "'" then "'/'" else url' + url' = "'" + ++ urlPrefix opts + ++ urlArgs + ++ queryArgs + + urlArgs = jsSegments + $ req ^.. reqUrl.path.traverse + + queryArgs = if null queryparams + then "" + else " + '?" ++ jsParams queryparams diff --git a/servant-js/test/Servant/JSSpec.hs b/servant-js/test/Servant/JSSpec.hs index 5ff60f9a..ec7bc000 100644 --- a/servant-js/test/Servant/JSSpec.hs +++ b/servant-js/test/Servant/JSSpec.hs @@ -17,6 +17,7 @@ import Servant.JS import qualified Servant.JS.Vanilla as JS import qualified Servant.JS.JQuery as JQ import qualified Servant.JS.Angular as NG +import qualified Servant.JS.Axios as AX import Servant.JSSpec.CustomHeaders type TestAPI = "simple" :> ReqBody '[JSON,FormUrlEncoded] String :> Post '[JSON] Bool @@ -55,13 +56,15 @@ data TestNames = Vanilla | JQueryCustom | Angular | AngularCustom + | Axios + | AxiosCustom deriving (Show, Eq) customOptions :: CommonGeneratorOptions -customOptions = defCommonGeneratorOptions { - successCallback = "okCallback", - errorCallback = "errorCallback" - } +customOptions = defCommonGeneratorOptions + { successCallback = "okCallback" + , errorCallback = "errorCallback" + } spec :: Spec spec = describe "Servant.JQuery" $ do @@ -71,9 +74,35 @@ spec = describe "Servant.JQuery" $ do generateJSSpec JQueryCustom (JQ.generateJQueryJSWith customOptions) generateJSSpec Angular (NG.generateAngularJS NG.defAngularOptions) generateJSSpec AngularCustom (NG.generateAngularJSWith NG.defAngularOptions customOptions) + generateJSSpec Axios (AX.generateAxiosJS AX.defAxiosOptions) + generateJSSpec AxiosCustom (AX.generateAxiosJSWith (AX.defAxiosOptions { withCredentials = True }) customOptions) angularSpec Angular - angularSpec AngularCustom + axiosSpec + --angularSpec AngularCustom + +axiosSpec :: Spec +axiosSpec = describe specLabel $ do + it "should add withCredentials when needed" $ do + let jsText = genJS withCredOpts $ listFromAPI (Proxy :: Proxy TestAPI) + output jsText + jsText `shouldContain` ("withCredentials: true") + it "should add xsrfCookieName when needed" $ do + let jsText = genJS cookieOpts $ listFromAPI (Proxy :: Proxy TestAPI) + output jsText + jsText `shouldContain` ("xsrfCookieName: 'MyXSRFcookie'") + it "should add withCredentials when needed" $ do + let jsText = genJS headerOpts $ listFromAPI (Proxy :: Proxy TestAPI) + output jsText + jsText `shouldContain` ("xsrfHeaderName: 'MyXSRFheader'") + where + specLabel = "Axios" + output _ = return () + withCredOpts = AX.defAxiosOptions { AX.withCredentials = True } + cookieOpts = AX.defAxiosOptions { AX.xsrfCookieName = Just "MyXSRFcookie" } + headerOpts = AX.defAxiosOptions { AX.xsrfHeaderName = Just "MyXSRFheader" } + genJS :: AxiosOptions -> [AjaxReq] -> String + genJS opts req = concat $ map (AX.generateAxiosJS opts) req angularSpec :: TestNames -> Spec angularSpec test = describe specLabel $ do @@ -92,8 +121,7 @@ angularSpec test = describe specLabel $ do output jsText jsText `shouldNotContain` "getsomething($http, " where - specLabel = "generateJS(" ++ (show test) ++ ")" - --output = putStrLn + specLabel = "AngularJS(" ++ (show test) ++ ")" output _ = return () testName = "MyService" ngOpts = NG.defAngularOptions { NG.serviceName = testName }