nstack-io / nstack-ios-sdk

MIT License
5 stars 10 forks source link

Missing api or documentation for testability when using NStack #71

Open jakobmygind opened 4 years ago

jakobmygind commented 4 years ago

HI guys,

My snapshot-tests especially but also unit tests rely somewhat on proper non-empty strings being used when running the tests targets. When the app code accesses the static tr/lo variable an empty Localizations object is returned, which causes my snapshots to render empty string and also unit tests which rely on a piece of state which uses strings from NStack, e.g. for interpolation, to fail, due to state not working as expected.

image

I am not sure when an empty Localizations()-object would be desirable, except if the generated object had default values corresponding to the json it was generated from.

I think we need a way to make the tr/lo variable return an object instantiated from json that we control in order for this to be fully testable. One could always wrap the tr/lo in client code to be able to return a controlled Localizations object, but it would be nicer if this was supported out of the box.

Is something like this in the works? @chriscombs @pbodsk

jakobmygind commented 4 years ago

An alternative to supporting this could be an option for the generator to not generate the accessor tr/lo variable or to keep it internal instead of public to allow for more control over how Localizations is accessed when used in a module.

Edit: I just found out there's a -standalone flag for the generator which prevents the addition of the static tr/lo, which eases wrapping of Localizations in client code, however built in support would still be nice ☺️

mariusc commented 4 years ago

Hi Jakob; we haven't had problems with this yet, but we see how this can be an issue; we'll look into this soon 😊

jakobmygind commented 4 years ago

Hi @mariusc Thanks!

I solved it for now using the -standalone flag along with this code that enables control over the tr instance

import NStackSDK

internal var lo: Localizations {
    guard let manager = NStack.sharedInstance.localizationManager else {
        return Localizations()
    }
    return try! manager.localization()
}

public internal (set) var tr: Localizations = { lo }()

#if DEBUG
public func setTranslations(_ localizations: Localizations) {
    tr = localizations
}

public func loadTranslationsFromJSON(_ filename: String, in bundle: Bundle) -> Localizations {
    let path = bundle.path(forResource: filename, ofType: "json")!

    let data = try! String(contentsOfFile: path).data(using: .utf8)!
    let dict = try! JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String: Any]
    let translationsData = try! JSONSerialization.data(withJSONObject: dict["data"]!, options: .fragmentsAllowed)

    let result = try! JSONDecoder().decode(Localizations.self, from: translationsData)
    return result
}

#endif

and then in my Test class

 class override func setUp() {
        super.setUp()
        let staticLocalizations = Shared.loadTranslationsFromJSON("Localizations_da-DK", in: Bundle(for: self))
        Shared.setTranslations(staticLocalizations)
    }