diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..8c98236
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "javascript-templates"]
+ path = javascript-templates
+ url = https://github.com/51degrees/javascript-templates
diff --git a/javascript-templates b/javascript-templates
new file mode 160000
index 0000000..1230271
--- /dev/null
+++ b/javascript-templates
@@ -0,0 +1 @@
+Subproject commit 12302710e81ea268c70158f4482f8f668c6dd316
diff --git a/javascript-templates/JavaScriptResource.mustache b/javascript-templates/JavaScriptResource.mustache
deleted file mode 100644
index fbddd60..0000000
--- a/javascript-templates/JavaScriptResource.mustache
+++ /dev/null
@@ -1,617 +0,0 @@
-fiftyoneDegreesManager = function() {
- 'use-strict';
- var json = {{&_jsonObject}};
- var parameters = {{&_parameters}};
- var sessionId = "{{&_sessionId}}";
- var sessionKey = "{{_objName}}_" + sessionId;
- this.sessionId = sessionId;
- var sequence = {{&_sequence}};
-
- // Log any errors returned in the JSON object.
- if(json.error !== undefined){
- console.log(json.error);
- }
-
- // Log any warnings returned in the JSON object.
- if (json.warnings !== undefined) {
- console.log(json.warnings);
- }
-
- // Set to true when the JSON object is complete.
- var completed = false;
-
- // changeFuncs is an array of functions. When onChange is called and passed
- // a function, the function is registered and is called when processing is
- // complete.
- var changeFuncs = [];
-
- // Counter is used to count how many pieces of callbacks are expected. Every
- // time the completedCallback method is called, the counter is decremented
- // by 1.
- var callbackCounter = 0;
-
- // Array of JavaScript properties that have started evaluation.
- var jsPropertiesStarted = [];
-
- // startsWith polyfill.
- var startsWith = function(source, searchValue) {
- return source.lastIndexOf(searchValue, 0) === 0;
- }
-
- // endsWith polyfill.
- var endsWith = function(source, searchValue) {
- return source.substring(source.length - searchValue.length, source.length) === searchValue;
- }
-
- var clearCache = function() {
- if (sessionStorage) {
- for (i = 0; i < sessionStorage.length; i++) {
- key = sessionStorage.key(i);
- if (startsWith(key, sessionKey)) {
- sessionStorage.removeItem(key);
- }
- }
- }
- }
-
- var loadParameters = function() {
- if (sessionStorage) {
- var parametersString = sessionStorage.getItem(sessionKey + "_parameters");
- if (parametersString) {
- parameters = JSON.parse(parametersString);
- }
- }
- return parameters;
- }
-
- var saveParameters = function(sourceParams) {
- if (sourceParams) {
- parameters = sourceParams
- }
-
- if (sessionStorage) {
- var parametersString = JSON.stringify(parameters);
- sessionStorage.setItem(sessionKey + "_parameters", parametersString);
- }
- }
-
- // Get stored values with the '51D_' prefix that have been added to the request
- // and return the data as key value pairs. This method is needed to extract
- // stored values for inclusion in the GET or POST request for situations
- // where CORS will prevent them from being sent to third parties.
- var getFodSavedValues = function(){
- let fodValues = {};
- {{#_enableCookies}}
- {
- let keyValuePairs = document.cookie.split(/; */);
- for(let nextPair of keyValuePairs) {
- let firstEqualsLocation = nextPair.indexOf('=');
- let name = nextPair.substring(0, firstEqualsLocation);
- if(startsWith(name, "51D_")){
- let value = nextPair.substring(firstEqualsLocation+1);
- fodValues[name] = value;
- }
- }
- };
- {{/_enableCookies}}
- {{^_enableCookies}}
- {
- // Collect values from session storage
- let session51DataPrefix = sessionKey + "_data_";
- for(let i = 0, n = window.sessionStorage.length; i < n; ++i) {
- let nextKey = window.sessionStorage.key(i);
- if(startsWith(nextKey, session51DataPrefix)){
- let value = window.sessionStorage[nextKey];
- fodValues[nextKey.substring(session51DataPrefix.length)] = value;
- }
- }
- };
- {{/_enableCookies}}
- return fodValues;
- };
-
- // Extract key value pairs from the '51D_' prefixed values and concatenates
- // them to form a query string for the subsequent json refresh.
- var getParametersFromStorage = function(){
- var fodValues = getFodSavedValues();
- var keyValuePairs = [];
- for (var key in fodValues) {
- if (fodValues.hasOwnProperty(key)) {
- // Url encode the value.
- // This is done to ensure that invalid characters (e.g. = chars at the end of
- // base 64 encoded strings) reach the server intact.
- // The server will automatically decode the value before passing it into the
- // Pipeline API.
- keyValuePairs.push(key+"="+encodeURIComponent(fodValues[key]));
- }
- }
- return keyValuePairs;
- };
-
- // Fetch a value safely from the json object. If a key somewhere down the
- // '.' separated hierarchy of keys is not present then 'undefined' is
- // returned rather than letting an exception occur.
- var getFromJson = function(key, allowObjects, allowBooleans) {
- var result = undefined;
- if(typeof allowObjects === 'undefined') { allowObjects = false; }
- if(typeof allowBooleans === 'undefined') { allowBooleans = false; }
-
- if (typeof(key) === 'string') {
- var functions = json;
- var segments = key.split('.');
- var i = 0;
- while (functions !== undefined && i < segments.length) {
- functions = functions[segments[i++]];
- }
- if (typeof(functions) === "string") {
- result = functions;
- } else if (allowBooleans && typeof(functions) === "boolean") {
- result = functions;
- } else if (allowObjects && typeof functions === 'object' && functions !== null) {
- result = functions;
- }
- }
- return result;
- }
-
- // Executed at the end of the processJSproperties method or for each piece
- // of JavaScript which has 51D code injected. When there are 0 pieces of
- // JavaScript left to process then reload the JSON object.
- var completedCallback = function(resolve, reject){
- callbackCounter--;
- if (callbackCounter === 0) {
-{{#_updateEnabled}}
- processRequest(resolve, reject);
-{{/_updateEnabled}}
- } else if (callbackCounter < 0){
- reject('Too many callbacks.');
- }
- }
-
- // Executes any JavaScript contained in the JSON data. Session storage is
- // used to check the process state of the JavaScript property, if the name
- // of the property exists as a key then it has been processed. If all the
- // processed JavaScript properties have been flagged as processed already
- // then session storage is checked again for a JSON payload. If it exists
- // then this is loaded into the managers internal data store. If not or if
- // JavaScript properties have been processed then the call-back is
- // processed with any new evidence produced by the JavaScript properties.
- // If JavaScript properties are processed then a key containing the name of
- // the JavaScript property is added to session storage. The complete flag is
- // set to true when there is no further JavaScript to be processed.
- var processJsProperties = function(resolve, reject, jsProperties, ignoreDelayFlag) {
- var executeCallback = true;
- var started = 0;
- var cached = 0;
- var cachedResponse = undefined;
- var toProcess = 0;
-
- // If there is no cached response and there are JavaScript code snippets
- // then process them and perform any call-backs required.
- if (jsProperties !== undefined && jsProperties.length > 0) {
-
- {{^_enableCookies}}
- let valueSetPrefix = new RegExp('document\\.cookie\\s*=\\s*(("([A-Za-z0-9_]+)\\s*=\\s*"\\s*\\+\\s*([^\\s};]+))|(`([A-Za-z0-9_]+)\\s*=\\s*\\$\\{([^}]+)\\}`))', 'g');
- let session51DataPrefix = sessionKey + "_data_";
- let sessionSetPatch = 'window.sessionStorage["' + session51DataPrefix + '$3$6"]=$4$7';
- {{/_enableCookies}}
-
- // Execute each of the JavaScript property code snippets using the
- // index of the value to access the value to avoid problems with
- // JavaScript returning erroneous values.
- for (var index = 0; index < jsProperties.length; index++) {
- var name = jsProperties[index];
- if (jsPropertiesStarted.indexOf(name) === -1) {
- var body = getFromJson(name);
-
- // If there is a body then this property should be processed.
- if (body) {
- toProcess++;
- }
- var isCached = sessionStorage && sessionStorage.getItem(sessionKey + "_property_" + name);
-
- if (!isCached) {
- // Create new function bound to this instance and execute it.
- // This is needed to ensure the scope of the function is
- // associated with this instance if any members are altered or
- // added. Avoids global scoped variables.
-
- var delay = getFromJson(name + 'delayexecution', false, true);
-
- if ((ignoreDelayFlag || (delay === undefined || delay === false)) &&
- body !== undefined) {
- var func = undefined;
- var searchString = '// 51D replace this comment with callback function.';
- completed = false;
- jsPropertiesStarted.push(name);
- started++;
-
- {{^_enableCookies}}
- body = body.replaceAll(valueSetPrefix, sessionSetPatch);
- {{/_enableCookies}}
-
- if (body.indexOf(searchString) !== -1){
- callbackCounter++;
- body = body.replace(/\/\/ 51D replace this comment with callback function./g, 'callbackFunc(resolveFunc, rejectFunc);');
- func = new Function('callbackFunc', 'resolveFunc', 'rejectFunc',
- "try {\n" +
- body + "\n" +
- "} catch (err) {\n" +
- "console.log(err);" +
- "}"
- );
- func(completedCallback, resolve, reject);
- executeCallback = false;
- } else {
- func = new Function(
- "try {\n" +
- body + "\n" +
- "} catch (err) {\n" +
- "console.log(err);" +
- "}"
- );
- func();
- }
- if (sessionStorage) {
- sessionStorage.setItem(sessionKey + "_property_" + name, true)
- }
- }
- } else {
- cached++;
- }
- }
- }
- }
- if(cached === toProcess || started === 0) {
- if (sessionStorage) {
- var cachedResponse = sessionStorage.getItem(sessionKey);
- if (cachedResponse) {
- loadJSON(resolve, reject, cachedResponse);
- executeCallback = false;
- }
- }
- }
-
- if (started === 0) {
- executeCallback = false;
- completed = true;
- }
- if (executeCallback) {
- callbackCounter = 1;
- completedCallback(resolve, reject);
- }
- };
-
-{{#_updateEnabled}}
-{{^_supportsFetch}}
- // Standard method to create a CORS HTTP request ready to send data.
- var createCORSRequest = function(method, url) {
- var xhr;
- try {
- xhr = new XMLHttpRequest();
- } catch(err){
- xhr = null;
- }
- if (xhr !== null && "withCredentials" in xhr) {
-
- // Check if the XMLHttpRequest object has a "withCredentials"
- // property.
- // "withCredentials" only exists on XMLHTTPRequest2 objects.
- xhr.open(method, url, true);
- } else if (typeof XDomainRequest != "undefined") {
-
- // Otherwise, check if XDomainRequest.
- // XDomainRequest only exists in IE, and is IE's way of making CORS
- // requests.
- xhr = new XDomainRequest();
- xhr.open(method, url);
- } else {
-
- // Otherwise, CORS is not supported by the browser.
- xhr = null;
- }
- return xhr;
- };
-{{/_supportsFetch}}
-{{/_updateEnabled}}
-
- // Check if the JSON object still has any JavaScript snippets to run.
- var hasJSFunctions = function() {
- for (var i = i; i < json.javascriptProperties; i++) {
- var body = getFromJson(json.javascriptProperties[i]);
- if (body !== undefined && body.length > 0) {
- return true;
- }
- }
- return false;
- }
-
- // Process the JavaScript properties.
- var process = function(resolve, reject){
- processJsProperties(resolve, reject, json.javascriptProperties, false);
- }
-
- var fireChangeFuncs = function(json) {
- for (var i = 0; i < changeFuncs.length; i++) {
- if (typeof changeFuncs[i] === 'function' &&
- changeFuncs[i].length === 1) {
- changeFuncs[i](json);
- }
- }
- }
-
-{{#_updateEnabled}}
- // Process the response as json and call the resolve method.
- var loadJSON = function(resolve, reject, responseText) {
- json = JSON.parse(responseText);
-
- if (hasJSFunctions()) {
- // json updated so fire 'on change' functions
- // before executing any new JS properties that
- // have come back.
- fireChangeFuncs(json);
- process(resolve, reject);
- } else {
- completed = true;
- // json updated so fire 'on change' functions
- // This must happen after completed = true in order
- // for 'complete' functions to fire.
- fireChangeFuncs(json);
- resolve(json);
- }
- }
-
- // Sends a POST request to the call-back URL to retrieve and updated
- // JSON payload from the cloud service. A POST request is used so that
- // parameters can be passed in the request body, this is to get around
- // the limitations on the length of query strings. As POST requests are not
- // cached by browsers, the result of the POST request is stored in session
- // storage on a successful response. This can then be checked before making
- // repeat requests to the call-back URL.
- // Any saved value parameters that have been set by the executed JavaScript
- // properties are added to the list of parameters, this list is then
- // serialized as Form Data and sent in the POST body to the call-back URL,
- // refreshing the JSON data. The new JSON is then loaded if the request is
- // returned with a success status code. If there was a problem then the
- // session storage items are invalidated and reject is called.
- var processRequest = function(resolve, reject){
- loadParameters();
-
- // Get additional parameters in case they are not sent
- // by the browser.
- var savedValueParams = getParametersFromStorage();
- for(var savedValueIndex in savedValueParams) {
- var parts = savedValueParams[savedValueIndex].split('=');
- parameters[parts[0]] = parts[1];
- }
-
- saveParameters();
-
- var params = [];
- for (var param in parameters) {
- if (parameters.hasOwnProperty(param)) {
- params.push(param+"="+parameters[param])
- }
- }
-
- // Add the session and sequence to the request
- if (sessionId) {
- params.push("session-id=" + sessionId);
- }
- if (sequence) {
- params.push("sequence=" + sequence);
- }
-
- var postBody = "";
- if (params.length > 0) {
- postBody = params.join('&').replace(/%20/g, '+');
- }
-
-{{#_supportsFetch}}
- fetch('{{{_url}}}', {
- method: 'POST',
- mode: 'cors',
- headers: {
- 'Content-Type': 'application/x-www-form-urlencoded',
- },
- body: postBody
- })
- .then(response => {
- return response.text();
- })
- .then(responseText => {
-{{/_supportsFetch}}
-{{^_supportsFetch}}
- // Request callback URL with additional parameters.
- var xhr = createCORSRequest('POST', '{{{_url}}}');
-
- // If there is no support for HTTP requests then call reject and throw
- // a no CORS support error.
- if (!xhr) {
- reject(new Error('CORS not supported'));
- return;
- }
-
- // Add the HTTP header for POST form data.
- xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
- xhr.setRequestHeader('Accept', 'application/json');
-
- xhr.onload = function () {
-
- // Get the response body from the request.
- var responseText = xhr.responseText;
-
-{{/_supportsFetch}}
- // Cache the response text.
- if (sessionStorage) {
- sessionStorage.setItem(sessionKey, responseText);
- }
- // Load the JSON object from the response text
- loadJSON(resolve, reject, responseText);
- // Increment the sequence on a successful request
- sequence++;
-{{#_supportsFetch}}
- })
- .catch(error => {
- // Invalidate the cache on error.
- clearCache();
- reject(error);
- });
-{{/_supportsFetch}}
-{{^_supportsFetch}}
- };
-
- xhr.onerror = function () {
- // An error occurred with the request. Invalidate the cache and
- // return the details in the call to reject method.
- clearCache();
- reject(Error(xhr.statusText));
- };
-
- // Send the GET request.
- xhr.send(postBody);
-{{/_supportsFetch}}
- }
-{{/_updateEnabled}}
-
- // Function logs errors, used to 'reject' a promise or for error callbacks.
- var catchError = function(value) {
- console.log(value.message || value);
- }
-
- // Populate this instance of the FOD object with getters to access the
- // properties. If the value is null then get the noValueMessage from the
- // JSON object corresponding to the property.
- var update = function(data){
- var self = this;
- Object.getOwnPropertyNames(data).forEach(function(key) {
- self[key] = {};
- for(var i in data[key]){
- var obj = self[key];
- (function(i) {
- Object.defineProperty(obj, i, {
- get: function (){
- if(data[key][i] === null && (i !== "javascriptProperties")){
- return data[key][i + "nullreason"];
- } else {
- return data[key][i];
- }
- }
- })
- })(i);
- }
- });
- }
-
-{{#_hasDelayedProperties}}
- // Get the JS property(s) that, when evaluated, will populate
- // evidence that can be used to determine the value of the
- // supplied property.
- // The supplied name can either be a complete property name or a top level
- // aspect name.
- // Where the aspect name is given, ALL evidence properties under that
- // key will be returned.
- // Example property names are 'location.country' or 'devices.profiles.hardwarename'
- // Example aspect names are 'location' or 'devices'
- var getEvidenceProperties = function (name) {
- var evidenceProperties = getFromJson(name + 'evidenceproperties');
- if(typeof evidenceProperties === "undefined") {
- var item = getFromJson(name, true);
- evidenceProperties = getEvidencePropertiesFromObject(item);
- }
- return evidenceProperties;
- }
-
- // Get all values in any 'evidenceproperty' fields on this object
- // or sub-objects.
- var getEvidencePropertiesFromObject = function (dataObject) {
- evidenceProperties = [];
-
- for (var prop in dataObject) {
- if (dataObject.hasOwnProperty(prop)) {
- var value = dataObject[prop];
- // Property name ends with 'evidenceproperties' so is
- // what we're looking for.
- // Add the values to the array if we don't already have it.
- if (value !== null && Array.isArray(value) && endsWith(prop, 'evidenceproperties')) {
- value.forEach(function(item, index) {
- if(evidenceProperties.indexOf(item) === -1) {
- evidenceProperties.push(item);
- }
- });
- }
- // Item is an object so recursively call this method
- // and add any resulting evidence properties to the list.
- else if(typeof value === 'object' && value !== null) {
- getEvidencePropertiesFromObject(value).forEach(function(item, index) {
- if(evidenceProperties.indexOf(item) === -1) {
- evidenceProperties.push(item);
- }
- });
- }
- }
- }
-
- return evidenceProperties;
- }
-{{/_hasDelayedProperties}}
-
-{{#_supportsPromises}}
- this.promise = new Promise(function(resolve, reject) {
- process(resolve,reject);
- });
-{{/_supportsPromises}}
-
- this.onChange = function(resolve) {
- changeFuncs.push(resolve);
- }
-
- this.complete = function(resolve, properties) {
-{{#_hasDelayedProperties}}
- // If properties is set then check if we need to kick off
- // processing of anything.
- if(typeof properties !== "undefined") {
- // If properties is a string then split on comma to produce
- // an array of one or more key names.
- if(typeof properties === "string") {
- properties = properties.split(',');
- }
- if(Array.isArray(properties)) {
- properties.forEach(function(key, i) {
- // We pass an empty function rather than 'resolve' because we
- // don't want to call resolve when a single evidence function
- // evaluates but after all of them have completed.
- // This is handled by the 'if(complete)' code below.
- processJsProperties(function(json) {}, catchError, getEvidenceProperties(key), true);
- });
- }
- }
-
-{{/_hasDelayedProperties}}
- if(completed){
- resolve(json);
- }else{
- this.onChange(function(data) {
- if(completed){
- resolve(data);
- }
- })
- }
- };
-
- // Update this instance with the initial JSON payload.
- update.call(this, json);
-{{#_supportsPromises}}
- var parent = this;
- this.promise.then(function(value) {
- // JSON has been updated so replace the current instance.
- update.call(parent, value);
- completed = true;
- }).catch(catchError);
-{{/_supportsPromises}}
-{{^_supportsPromises}}
- process(function(json) {}, catchError);
-{{/_supportsPromises}}
-}
-
-var {{_objName}} = new fiftyoneDegreesManager();
\ No newline at end of file
diff --git a/javascript-templates/README.md b/javascript-templates/README.md
deleted file mode 100644
index 71f735a..0000000
--- a/javascript-templates/README.md
+++ /dev/null
@@ -1,8 +0,0 @@
-## Purpose
-
-Store shared (mustache) templates to be used by the implementation of `JavaScriptBuilderElement` and other components across the languages.
-
-## Background
-
-The [language-independent specification](https://github.com/51Degrees/specifications) describes how JavaScriptBuilderElement is used [here](https://github.com/51Degrees/specifications/blob/36ff732360acb49221dc81237281264dac4eb897/pipeline-specification/pipeline-elements/javascript-builder.md). The mechanics is: javascript file is requested from the server (on-premise web integration) and is created from this mustache template by the JavaScriptBuilderElement. It then collects more evidence, sends it to the server and upon response calls a callback function providing the client with more precise device data.
-
diff --git a/phpunit.xml b/phpunit.xml
index 47eb87b..08da1c1 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -4,6 +4,7 @@
tests/CoreTests.php
tests/ExampleTests.php
tests/JavaScriptBundlerTests.php
+ tests/EnableCookiesTests.php
tests/FlowDataTests.php
tests/SetHeaderTests.php
diff --git a/src/JavascriptBuilderElement.php b/src/JavascriptBuilderElement.php
index a15b9b4..4d93f8d 100644
--- a/src/JavascriptBuilderElement.php
+++ b/src/JavascriptBuilderElement.php
@@ -168,6 +168,11 @@ public function processInternal(FlowData $flowData): void
$vars['_sessionId'] = $flowData->evidence->get('query.session-id');
$vars['_sequence'] = $flowData->evidence->get('query.sequence');
+ $enableCookies = $flowData->evidence->get('query.fod-js-enable-cookies');
+ if ($enableCookies !== null) {
+ $vars['_enableCookies'] = strtolower($enableCookies) === 'true';
+ }
+
$jsParams = [];
foreach ($params as $param => $paramValue) {
$paramKey = explode('.', $param)[1];
diff --git a/tests/EnableCookiesTests.php b/tests/EnableCookiesTests.php
new file mode 100644
index 0000000..9db41cb
--- /dev/null
+++ b/tests/EnableCookiesTests.php
@@ -0,0 +1,102 @@
+ [
+ 'type' => 'javascript'
+ ]
+ ];
+
+ public function processInternal($flowData): void
+ {
+ $contents = [];
+
+ $contents['javascript'] = "document.cookie = 'some cookie value'";
+ $contents['normal'] = true;
+
+ $data = new ElementDataDictionary($this, $contents);
+
+ $flowData->setElementData($data);
+ }
+}
+
+class EnableCookiesTests extends TestCase
+{
+ public static function provider_testJavaScriptCookies()
+ {
+ return [
+ [false, false, false],
+ [true, false, false],
+ [false, true, true],
+ [true, true, true]
+ ];
+ }
+
+ /**
+ * Test that the cookie settings are respected correctly.
+ * @dataProvider provider_testJavaScriptCookies
+ */
+ #[DataProvider("provider_testJavaScriptCookies")]
+ public function testJavaScriptCookies($enableInConfig, $enableInEvidence, $expectCookie)
+ {
+ $jsElement = new JavascriptBuilderElement([
+ 'enableCookies' => $enableInConfig
+ ]);
+
+ $pipeline = (new PipelineBuilder())
+ ->add(new CookieElement())
+ ->add(new SequenceElement())
+ ->add(new JsonBundlerElement())
+ ->add($jsElement)
+ ->build();
+
+ $flowData = $pipeline->createFlowData();
+ $flowData->evidence->set('query.fod-js-enable-cookies', $enableInEvidence ? 'true' : 'false');
+ $flowData->process();
+
+ $js = $flowData->javascriptbuilder->javascript;
+ $matches = substr_count($js, 'document.cookie');
+ if ($expectCookie === true) {
+ $this->assertSame(2, $matches);
+ }
+ else {
+ $this->assertSame(1, $matches);
+ }
+ }
+}
diff --git a/tests/SetHeaderTests.php b/tests/SetHeaderTests.php
index 7818a53..9461d48 100644
--- a/tests/SetHeaderTests.php
+++ b/tests/SetHeaderTests.php
@@ -31,6 +31,7 @@
use fiftyone\pipeline\core\tests\classes\TestPipeline;
use fiftyone\pipeline\core\Utils;
use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\Attributes\DataProvider;
class SetHeaderTests extends TestCase
{
@@ -80,11 +81,10 @@ public static function provider_testGetResponseHeaderValue()
/**
* Test response header value to be set for UACH.
- *
+ *
* @dataProvider provider_testGetResponseHeaderValue
- * @param mixed $device
- * @param mixed $expectedValue
*/
+ #[DataProvider("provider_testGetResponseHeaderValue")]
public function testGetResponseHeaderValue($device, $expectedValue)
{
$setHeaderPropertiesDict = [
@@ -142,11 +142,9 @@ public static function provider_testGetResponseHeaderName_Valid()
/**
* Test get response header function for valid formats.
- *
* @dataProvider provider_testGetResponseHeaderName_Valid
- * @param mixed $data
- * @param mixed $expectedValue
*/
+ #[DataProvider("provider_testGetResponseHeaderName_Valid")]
public function testGetResponseHeaderNameValid($data, $expectedValue)
{
$setHeaderElement = new SetHeaderElement();
@@ -166,11 +164,9 @@ public static function provider_testGetResponseHeaderName_InValid()
/**
* Test get response header function for valid formats.
- *
* @dataProvider provider_testGetResponseHeaderName_InValid
- * @param mixed $data
- * @param mixed $expectedValue
*/
+ #[DataProvider("provider_testGetResponseHeaderName_InValid")]
public function testGetResponseHeaderNameInValid($data, $expectedValue)
{
$setHeaderElement = new SetHeaderElement();