Friday 9 May 2008

Use JSON for fixture output

When setting up automated web tests sometimes you need to parse generated data (ids, dates etc). An easy solution that works both from java and javascript and is therefore compatible with Selenium, Canoo and HttpUnit is to output the fixtures as JSON.


class FixtureController {

def index = {
Class clazz = grailsApplication.getClassForName(params.id)
List domainObjects = clazz.list(sort:'id', order:'asc')
Map model = getJsonModel(domainObjects)
render(view:'index', model: model)
}

private Map getJsonModel(List items) {
Map model = new HashMap()
items.each { item ->
JodaFriendlyJSON converter = new JodaFriendlyJSON(target: item);
converter.setRenderDomainClassRelations(true)
model.get('json', []).add(converter)
}
return model
}
}

// Only necessary if you use Joda rather than java.util.Date
// otherwise just use grails.converters.deep.JSON
class JodaFriendlyJSON extends grails.converters.deep.JSON {
protected void bean(Object o) {
if (o.class.isAssignableFrom(DateTime.class)) {
value(o.toString("dd/MM/yyyy HH:mm:ss"))
} else {
super.bean(o);
}
}
}


Now you can get whatever attribute you like from any of your domain objects just by navigating to /fixture/index/DomainObjectClass.

Java example:

protected String getConversationIdFromFixturePage(WebResponse resp, Integer index) {
JSONArray jsonArray = new JSONArray(resp.getElementWithID('json').getText())
return jsonArray.getJSONObject(index).getJSONObject('id')
}


Selenium Example:

// Add this to a custom extension

function parseJson(json) {
var x; eval('x = ' + json); return x;
}

Selenium.prototype.getJson = function(locator) {
return parseJson(this.getText(locator));
}

// Then do something like this in your selenium test
<tr>
<td>storeJson</td>
<td>//div[@id='json']</td>
<td>conversations</td>
</tr>
<tr>
<td>storeEval</td>
<td>{storedVars.conversations[0].id}</td>
<td>conversationId</td>
</tr>


Not groovy / grails related, but useful none the less

No comments: