How to intentionally fail $model->save() for testing? - yii2

I have this code in my controller class:
public function actionRevoke($id) {
$model = Token::findById($id);
$model->revoked_at = new Expression('NOW()');
if ($model->save()) {
Yii::$app->getSession()->setFlash('success', 'Revoked token');
} else {
Yii::$app->getSession()->setFlash('danger', 'Failed to revoke token');
}
return $this->render('revoke',['model' => $this]);
}
Now, running CodeCeption with code coverage, it tells me, the part with setFlash('danger',...) is not covered by tests.
How can I intentionally fail the $model->save() to trigger the setFlash('danger,...) instruction?
I would really like it, if I do not need to add extra code to my Controller exclusively for testing. So in particular, I don't want something like if ($model->save() && !defined('TEST_FAIL_SAVE')) { if it can be avoided.

The solution was (as suggested by #scaisEdge) to use validation rules. I added a rule, which enforces the length of $model->token to exactly 36. My application generates only tokens exactly 36 chars long. In my test, I use update the row in the database to show abcd as token, which is clearly less than 36 chars.
As this change is made on database level, it bypasses the validation of Yii and is committed to the database.
During the test, it changes the value of $model->revoked_at and attempts to save it, but fails the validation because $model->token is too short.
Here is the relevant part in the test function, the code of the controller was not changed:
public function revokeToken(FunctionalTester $I){
// login and navigation to relevant page
Yii::$app->db->createCommand()->update('tokens',['token' => 'abcd'],['id' => 201 ])->execute();
$I->click('a.btn.btn-danger'); /* click the 'revoke' button, this triggers actionRevoke($id) */
$I->seeFlash('Failed to revoke token'); /* expect a flash message */
}

Related

Is it possible to inspect the values entered in the Adyen payment widget and run validations against those values? And give error states?

I'm looking to set my own validations on my Adyen payment module. Specifically I want to eliminate people's ability to insert incorrect characters in card holder name field (like emojis, etc).
You are able to customize the validation logic implementing one of the handlers
onChange: (state, component) => {
// triggered at every change
console.error("onChange " + JSON.stringify(state.data));
},
onSubmit: (state, component) => {
// triggered upon submit
console.error("onSubmit " + JSON.stringify(state.data));
// grab holderName
var holderName = state.data.paymentMethod.holderName;
// apply your validation...
if(validationOk) {
makePayment(state.data)
// etc etc
}
}
Check Web Dropin integration guide. Make sure to check which version you are using (to refer to the relevant documentation), however the workflow is similar.

Only one type of action can execute?

I going to show my problem with an example:
I have a button. When clicked, it creates a mail draft based on the TextInputFields in the add-on.
I have a validate function, which can say if the fields filled right or not.
If I want to notify the user somehow about the wrong fields, I have to create a notify or rebuild the card with error information. These actions can be returned in a normal Action, but not with a composeAction (because composeAction has to return with builded draft), so I have to register a composeAction and a simple action to the button.
When I clicked this kind of button, only one of the action execute and the other do nothing.
Some code about how I tried to implement:
section.addWidget(CardService.newTextButton()
.setText('Validate and Create')
.setComposeAction(CardService.newAction().setFunction('doIt'), CardService.ComposedEmailType.STANDALONE_DRAFT)
.setOnClickAction(CardService.newAction().setFunction('notify')));
ActionFunctions:
function doIt(event){
validate the event['formInput'] object;
if(valid the formInput)
create andr return the draft;
else
return null;
}
function notify(event){
validate the event['formInput'] object;
if(valid the formInput)
return null;
else
return notify or rebuilded card with error info;
}
Mostly the simple action run, and the compose do nothing. If I place Logger.log() functions in the callback function, only one appears on api log.
Anyone have tried before validate and create draft at the same click?
How about this:
var action=CardService.newAction().setFunctionName('myFunction');
var validateCreateButton=CardService.newTextButton()
.setText('Validate & Create')
.setOnClickAction(action);
section.addWidget(validateCreateButton);
function myFunction(e) {
doit(e);
notify(e);
}

onClick communication between content and background scripts not working

I am making an application that highlights key words in the current page after the user clicks my icon. I am trying to communicate between my content scripts and background script. However,my code is not working. Does anyone know how it should be written?
Here is my content script:
chrome.extension.onRequest.addListener(function(active,sender,sendResponse){
if(active.length>0){
jQuery(document).ready(function($) {
//rest of word highlighting code
}
})
here is my background.js :
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.extension.sendRequest(active);
});
Do not use the deprecated chrome.extension.sendRequest and matching events. They are old, broken and not supported, which is quite clearly said in the documentation - which shows that you did not go and read it.
The correct ones to use are chrome.runtime.sendMessage and .onMessage, but otherwise the signature is the same.
Well.. Why did you expect that to work? (unless you're not really showing us all relevant code, which is.. not helpful)
chrome.browserAction.onClicked.addListener(function(tab) {
// There is no "active" in the code anywhere to this point.
// It is treated like a variable name, one that was not yet used,
// so its contents are "undefined", and that's what you're sending.
chrome.runtime.sendMessage(active);
// Equivalent code: chrome.runtime.sendMessage(undefined);
});
And on the receiving side:
chrome.runtime.onMessage.addListener(function(active,sender,sendResponse){
// So, here "active" is undefined. It does not have a length
// parameter, and as such causes a fatal exception
// "Cannot read property 'length' of undefined"
// that you might have seen in the console of the page
if(active.length>0){
/* something */
}
})
Whatever you send is usually, but not always, an object (well, it must be JSON-serializable). If you just want to trigger something and not pass any data, there are 2 often-used conventions, either is fine:
Pass command as a value.
// Sender
chrome.runtime.sendMessage({action: "active"});
// Receiver
chrome.runtime.onMessage.addListener(function(message,sender,sendResponse){
if(message.command == "active"){
/* something */
}
// or, useful if you have many different commands:
switch(message.command){
case "active":
/* something */
break;
}
});
Set a boolean in the message:
// Sender
chrome.runtime.sendMessage({active: true});
// Receiver
chrome.runtime.onMessage.addListener(function(message,sender,sendResponse){
if(message.active){
/* something */
}
});

OWA Signature Update with Exchange Web Services

We're using Exchange Web Services to set user signature in Outlook Web Access. It works great, we see the signature under Options>Settings and the "Automatically include my signature on messages I send" check box is checked. We also set this programmatically.
However, when the user creates a new e-mail message in OWA the signature does not show up. A work around for this is to go to Options>Setting, uncheck the "Automatically include my signature on messages I send" check box , Save, check the check box again and save.
The code we use to set the signature looks something like this:
Folder rootFolder;
UserConfiguration OWAConfig;
rootFolder = Folder.Bind(service, WellKnownFolderName.Root);
OWAConfig = UserConfiguration.Bind(service, "OWA.UserOptions",rootFolder.ParentFolderId, UserConfigurationProperties.All);
OWAConfig.Dictionary["signaturehtml"] = "Hello World";
OWAConfig.Dictionary["autoaddsignature"] = "True";
OWAConfig.Update();
Any idea how to get around this problem?
I have some old code that does the same thing which is working fine. I have pasted the code below. There are a few minor differences between my code and yours. I am not sure if they make a difference but you may want to try it out. Here is an extract of my code with the differences highlighted with a comment:
private void SetSettingValue(UserConfiguration owaConfig, string propName, object propValue)
{
if (owaConfig.Dictionary.ContainsKey(propName))
{
owaConfig.Dictionary[propName] = propValue;
}
else
{
// Adds a key if it does not explicitly exist.
// I am not sure if it makes a difference.
owaConfig.Dictionary.Add(propName, propValue);
}
}
public void AddSignature()
{
// Extract
UserConfiguration OWAConfig = UserConfiguration.Bind(
service,
"OWA.UserOptions",
WellKnownFolderName.Root, // Binding to Root and not Root.ParentFolderId.
UserConfigurationProperties.Dictionary // Binds to Dictionary and not to All.
);
SetSettingValue(OWAConfig, "autoaddsignature", true);
SetSettingValue(OWAConfig, "signaturehtml", html);
OWAConfig.Update();
}

Grails 2.0.4 webflow "type mismatch" exception

I'm still pretty new to Grails and I'm developing an online survey. I decided to use web flow and I have been running into many issues. I'm trying to pass the survey id from the gsp page to the flow controller. This works perfectly fine on any other controller action but whenever I do it to the action for the start state of the flow I always get the same error. I've followed a tutorial in a text book that does this the EXACT same way and I'm running out of ideas.
here is the link from the gsp page:
<g:link controller="surveyPage" action="beginTest" id="${survey.id}">
${survey.surveyName}
</g:link>
and here is the flow with the start state
def beginTestFlow = {
showSurvey{
def survey = Survey.get(params.id)
on("cancel").to "cancelSurvey"
on("continueSurvey").to "nextQuestion"
}
cancelSurvey { redirect(controller:"surveyPage") }
}
it always throws the exception:
argument type mismatch on the line with
def survey = Survey.get(params.id)
I've also tried:
flow.survey = Survey.get(params.id)
or even:
flow.survey = Survey.get(session.survey.id)
always the same error. Also, I made sure class Survey implements Serializable. I've copied and pasted the same code into a different action with the same controller and it works flawlessly. Any ideas to what is different with the web flow?
You can't put code like that directly inside a state definition, you need to use an action state or an onEntry block
def beginTestFlow = {
showSurvey{
onEntry {
flow.survey = Survey.get(params.id)
}
on("cancel").to "cancelSurvey"
on("continueSurvey").to "nextQuestion"
}
cancelSurvey { redirect(controller:"surveyPage") }
}
The onEntry block will fire every time the showSurvey state is entered. If instead you want some logic to be run just once at the start of the whole flow (for example if some later transition might re-enter the initial state), you can use a flow-level onStart block instead:
def beginTestFlow = {
onStart {
flow.survey = Survey.get(params.id)
}
showSurvey{
on("cancel").to "cancelSurvey"
// ...
Ivo Houbrechts wrote an excelent tutorial about grails 2.0 webflow. You can read it here:
http://livesnippets.cloudfoundry.com/docs/guide/